views.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. import json
  2. from django.core.mail import send_mail
  3. import locale
  4. import logging
  5. from django.contrib.auth import login
  6. from django.core.serializers.json import DjangoJSONEncoder
  7. from django.core.urlresolvers import reverse
  8. from django.conf import settings
  9. from django.forms import model_to_dict
  10. from django.http import HttpResponseRedirect, HttpResponse
  11. from django.shortcuts import render_to_response, get_object_or_404
  12. from django.template import RequestContext
  13. from accounts.forms import (
  14. ProfileSecondaryAddressForm,
  15. ProfileUpdateForm,
  16. ProfileCreateForm,
  17. )
  18. from accounts.profile import get_profile, get_profile_secondary_address
  19. from accounts import utils as account_utils
  20. from cart.cart import add_to_cart, remove_subscriptions
  21. from catalog import models as catalog_models
  22. from catalog.models import Subscription
  23. from catalog.utils import get_type_by_profile, get_type
  24. from . import constants
  25. from . import forms
  26. from . import utils
  27. LOG = logging.getLogger(__name__)
  28. STOREFRONT_HELP_TO = getattr(settings, "STOREFRONT_HELP_TO")
  29. def storefront_help(request):
  30. """ Store Help """
  31. form = forms.HelpForm(request.POST or None)
  32. if request.method == "POST":
  33. if form.is_valid():
  34. message = "".join(
  35. [
  36. "{0}: {1}\n".format(key, value)
  37. for key, value in form.cleaned_data.iteritems()
  38. ]
  39. )
  40. LOG.info(
  41. "Help Form Contents (Sending To: {0}): {1}".format(
  42. STOREFRONT_HELP_TO, message
  43. )
  44. )
  45. send_mail(
  46. "PBP Community Storefront Feedback",
  47. message,
  48. "subscriptions@pbp.me",
  49. [STOREFRONT_HELP_TO],
  50. fail_silently=True,
  51. )
  52. return HttpResponseRedirect(reverse("help_confirm"))
  53. return render_to_response(
  54. "storefront/help.html", {"form": form}, context_instance=RequestContext(request)
  55. )
  56. def storefront_help_confirm(request):
  57. """ Store Help Confirmation Page"""
  58. return render_to_response(
  59. "storefront/help_confirm.html", context_instance=RequestContext(request)
  60. )
  61. def storefront_privacy(request):
  62. """ Store Help """
  63. return render_to_response(
  64. "storefront/privacy.html", context_instance=RequestContext(request)
  65. )
  66. def storefront_index(request):
  67. """ Store Front Home page """
  68. return render_to_response(
  69. "storefront/index.html", context_instance=RequestContext(request)
  70. )
  71. def category(request, category):
  72. """ Category page """
  73. # TODO: security, etc
  74. # TODO: sorting by price, or title.
  75. config = {
  76. "movie": catalog_models.Movie,
  77. "book": catalog_models.Book,
  78. "map": catalog_models.Map,
  79. }
  80. sort_type = {"p": "price", "-p": "-price", "t": "title", "-t": "-title"}
  81. sort = request.GET.get("sort", "t")
  82. sort_by = sort_type.get(sort)
  83. model = config.get(category)
  84. # sort by title or price, asc or desc default to title asc
  85. items = model.objects.active().order_by(sort_by)
  86. return render_to_response(
  87. "storefront/category.html",
  88. {"items": items, "category": category, "sort_by": sort_by},
  89. context_instance=RequestContext(request),
  90. )
  91. def item_price(request):
  92. """ Ajax call to return the item price """
  93. def _currency(value):
  94. """ convert value to a nice looking currency """
  95. try:
  96. locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
  97. except Exception:
  98. locale.setlocale(locale.LC_ALL, "")
  99. loc = locale.localeconv()
  100. return locale.currency(value, loc["currency_symbol"], grouping=True)
  101. response_data = "$N/A"
  102. if request.method == "POST":
  103. try:
  104. LOG.debug("Post info: {0}".format(request.POST))
  105. # use the form data to determine the shipping_type
  106. region1 = request.POST.get("region1", None)
  107. postal_code1 = request.POST.get("postal_code1", None)
  108. country_code1 = request.POST.get("country_code1", None)
  109. region2 = request.POST.get("region2", None)
  110. postal_code2 = request.POST.get("postal_code2", None)
  111. country_code2 = request.POST.get("country_code2", None)
  112. shipping_type = get_type(
  113. postal_code1,
  114. region1,
  115. country_code1,
  116. postal_code2=postal_code2,
  117. region2=region2,
  118. country_code2=country_code2,
  119. )
  120. LOG.debug("Found shipping type as: {0}".format(shipping_type))
  121. # Recast the id values to searchable values
  122. title = request.POST.get("title", None)
  123. duration = request.POST.get("duration", None)
  124. shipping_method = request.POST.get("shipping_method", None)
  125. title = utils.get_value_by_index(utils.unique_titles(shipping_type), title)
  126. duration = utils.get_value_by_index(
  127. utils.unique_durations(shipping_type), duration
  128. )
  129. shipping_method = utils.get_value_by_index(
  130. utils.unique_shipping_methods(), shipping_method
  131. )
  132. LOG.debug(
  133. "{0}, {1}, {2}, {3}".format(
  134. title, duration, shipping_method, shipping_type
  135. )
  136. )
  137. try:
  138. # Renewals are the same price as regular. This might
  139. # need to change if that changes
  140. subscription = Subscription.objects.get(
  141. title=title,
  142. duration=duration,
  143. shipping_type=shipping_type,
  144. shipping_method=shipping_method,
  145. renewal=False,
  146. )
  147. response_data = _currency(subscription.price)
  148. except Subscription.DoesNotExist:
  149. pass
  150. except Exception, e:
  151. LOG.error(e)
  152. raise e
  153. return HttpResponse(
  154. json.dumps(response_data, cls=DjangoJSONEncoder),
  155. content_type="application/json",
  156. )
  157. def item_detail(request, sku):
  158. item = get_object_or_404(catalog_models.Item, sku=sku).child
  159. return render_to_response(
  160. "storefront/item_detail.html",
  161. {"item": item},
  162. context_instance=RequestContext(request),
  163. )
  164. def subscription_home(request):
  165. """ Subscription Home page """
  166. return render_to_response(
  167. "storefront/subscriptions_home.html", context_instance=RequestContext(request)
  168. )
  169. def choose_new_subscription(request, template="storefront/subscriptions_new.html"):
  170. """ View used to manage a new subscription """
  171. def _render(request, form, user_form, second_address_form, shipping_type):
  172. return render_to_response(
  173. template,
  174. {
  175. "form": form,
  176. "userform": user_form,
  177. "second_address": second_address_form,
  178. "type": shipping_type,
  179. },
  180. context_instance=RequestContext(request),
  181. )
  182. # set some sane defaults
  183. user = request.user
  184. subscription_initial = {"duration": 1}
  185. primary_initial = {"region": "ME", "country": "US"}
  186. secondary_initial = {}
  187. shipping_type = get_type(None, "ME", "US")
  188. if user.is_authenticated():
  189. profile = get_profile(user)
  190. secondary_address = get_profile_secondary_address(user)
  191. shipping_type = get_type_by_profile(profile)
  192. primary_initial = model_to_dict(user)
  193. primary_initial.update(model_to_dict(profile))
  194. secondary_initial = model_to_dict(secondary_address)
  195. user_form = ProfileUpdateForm(
  196. user, request.POST or None, initial=primary_initial, prefix="form2"
  197. )
  198. else:
  199. user_form = ProfileCreateForm(
  200. request.POST or None, initial=primary_initial, prefix="form2"
  201. )
  202. form = forms.SubscriptionForm(
  203. request.POST or None,
  204. initial=subscription_initial,
  205. shipping_type=shipping_type,
  206. prefix="form1",
  207. )
  208. second_address_form = ProfileSecondaryAddressForm(
  209. request.POST or None, initial=secondary_initial, prefix="form3"
  210. )
  211. if (
  212. request.method == "POST"
  213. and user_form.is_valid()
  214. and second_address_form.is_valid()
  215. ):
  216. # we've called is_valid for both the profile and address forms
  217. shipping_type = get_type(
  218. user_form.cleaned_data.get("postal_code", None),
  219. user_form.cleaned_data.get("region", None),
  220. user_form.cleaned_data.get("country", None),
  221. postal_code2=second_address_form.cleaned_data.get("postal_code", None),
  222. region2=second_address_form.cleaned_data.get("region", None),
  223. country_code2=second_address_form.cleaned_data.get("country", None),
  224. )
  225. form = forms.SubscriptionForm(
  226. request.POST or None,
  227. shipping_type=shipping_type,
  228. initial=subscription_initial,
  229. prefix="form1",
  230. )
  231. if form.is_valid():
  232. user = user_form.save(request=request)
  233. second_address_form.save(user=user)
  234. subscription = form.save()
  235. remove_subscriptions(request)
  236. add_to_cart(request, subscription, quantity=1)
  237. return HttpResponseRedirect(reverse("checkout"))
  238. return _render(request, form, user_form, second_address_form, shipping_type)
  239. def choose_gift_subscription(
  240. request, template="storefront/subscriptions_gift_subs.html"
  241. ):
  242. def render(subscription_form, gift_from_form, gift_to_form, gift_info_form):
  243. return render_to_response(
  244. template,
  245. {
  246. "form": subscription_form,
  247. "gift_from": gift_from_form,
  248. "gift_to": gift_to_form,
  249. "gift_info_form": gift_info_form,
  250. },
  251. context_instance=RequestContext(request),
  252. )
  253. # set some sane defaults
  254. shipping_type = get_type(None, "ME", "US")
  255. subscription_initial = {"duration": 1}
  256. gift_from_initial = {"region": "ME", "country": "US"}
  257. gift_to_initial = {"region": "ME", "country": "US"}
  258. user = request.user
  259. LOG.debug("Checking authentication status...")
  260. if user.is_authenticated():
  261. LOG.debug("User is authenticated...creating user specific forms.")
  262. gift_from_initial = model_to_dict(user)
  263. gift_from_initial.update(model_to_dict(user.get_profile()))
  264. shipping_type = get_type_by_profile(get_profile(user))
  265. gift_from_form = ProfileUpdateForm(
  266. user, request.POST or None, initial=gift_from_initial, prefix="form5"
  267. )
  268. else:
  269. LOG.debug("User is not authenticated...creating user creation forms.")
  270. gift_from_form = ProfileCreateForm(
  271. request.POST or None, initial=gift_from_initial, prefix="form5"
  272. )
  273. subscription_form = forms.SubscriptionForm(
  274. request.POST or None,
  275. shipping_type=shipping_type,
  276. initial=subscription_initial,
  277. prefix="form1",
  278. )
  279. gift_to_form = forms.GiftToForm(
  280. request.POST or None, initial=gift_to_initial, prefix="form2"
  281. )
  282. gift_info_form = forms.GiftInformationForm(request.POST or None, prefix="form4")
  283. if request.method == "POST" and gift_from_form.is_valid():
  284. LOG.debug("Processing POST data...")
  285. # we've called is_valid on the gift from form and since we are
  286. # here..it is. We intentionally have not called saved so that a user
  287. # isn't created yet as this would cause confusion if the other forms
  288. # do not validate. We need the data from the cleaned form to pass to
  289. # the Subscription form which will determine if the subscription type
  290. # is valid.
  291. shipping_type = get_type(
  292. gift_from_form.cleaned_data.get("postal_code", None),
  293. gift_from_form.cleaned_data.get("region", None),
  294. gift_from_form.cleaned_data.get("country", None),
  295. )
  296. subscription_form = forms.SubscriptionForm(
  297. request.POST or None,
  298. shipping_type=shipping_type,
  299. initial=subscription_initial,
  300. prefix="form1",
  301. )
  302. LOG.debug("Checking validity of forms....")
  303. if (
  304. gift_to_form.is_valid()
  305. and subscription_form.is_valid()
  306. and gift_info_form.is_valid()
  307. and gift_from_form.is_valid()
  308. ):
  309. LOG.debug("Forms are valid...processing.")
  310. gift_from_form.save(request=request)
  311. subscription = subscription_form.save()
  312. gift_to_form.save()
  313. gift_detail = gift_to_form.cleaned_data or {}
  314. gift_detail.update(gift_info_form.cleaned_data)
  315. remove_subscriptions(request)
  316. add_to_cart(request, subscription, gift_detail=gift_detail, quantity=1)
  317. return HttpResponseRedirect(reverse("checkout"))
  318. else:
  319. LOG.debug("Forms are not valid.")
  320. LOG.debug("subscription_form: {0}".format(subscription_form))
  321. LOG.debug("gift_from_form: {0}".format(gift_from_form))
  322. LOG.debug("gift_to_form: {0}".format(gift_to_form))
  323. LOG.debug("gift_info_form: {0}".format(gift_info_form))
  324. return render(subscription_form, gift_from_form, gift_to_form, gift_info_form)
  325. def change_of_address(request, template="storefront/subscriptions_change_address.html"):
  326. """ Submits a change of address form. If the user is not logged in, it
  327. also creates a new user account.
  328. """
  329. # set some sane defaults
  330. user = request.user
  331. primary_initial = {"region": "ME", "country": "US"}
  332. old_address_initial = {"region": "ME", "country": "US"}
  333. form = forms.ChangeOfAddressForm(
  334. request.POST or None, initial={"date_effective": constants.NEXT_ISSUE}
  335. )
  336. if user.is_authenticated():
  337. profile = get_profile(user)
  338. old_address_initial = model_to_dict(user)
  339. old_address_initial.update(model_to_dict(profile))
  340. old_address = forms.AddressForm(
  341. request.POST or None, initial=old_address_initial, prefix="form5"
  342. )
  343. new_address = ProfileUpdateForm(
  344. user, request.POST or None, initial=primary_initial, prefix="form2"
  345. )
  346. else:
  347. old_address = forms.AddressForm(
  348. request.POST or None, initial=old_address_initial, prefix="form5"
  349. )
  350. new_address = ProfileCreateForm(
  351. request.POST or None, initial=primary_initial, prefix="form2"
  352. )
  353. if request.method == "POST":
  354. if form.is_valid() and old_address.is_valid() and new_address.is_valid():
  355. new_address.save(request=request)
  356. # recast the title index from the form to the
  357. # actual title
  358. raw_title = form.cleaned_data.get("title", None)
  359. title = utils.get_value_by_index(utils.unique_titles(), raw_title)
  360. old_address_initial.update(old_address.cleaned_data)
  361. account_utils.send_change_of_address_email(
  362. title,
  363. form.cleaned_data.get("account_number", None),
  364. form.cleaned_data.get("date_effective", None),
  365. form.cleaned_data.get("from_date", None),
  366. form.cleaned_data.get("to_date", None),
  367. old_address_initial,
  368. new_address.cleaned_data,
  369. )
  370. return HttpResponseRedirect(
  371. reverse("subscriptions_address_change_complete")
  372. )
  373. return render_to_response(
  374. template,
  375. {"form": form, "old_address": old_address, "new_address": new_address},
  376. context_instance=RequestContext(request),
  377. )
  378. def change_of_address_complete(
  379. request, template="storefront/subscriptions_change_address_complete.html"
  380. ):
  381. user = request.user
  382. new_address_initial = model_to_dict(user)
  383. new_address_initial.update(model_to_dict(user.get_profile()))
  384. new_address = forms.AddressForm(initial=new_address_initial)
  385. return render_to_response(
  386. template, {"new_address": new_address}, context_instance=RequestContext(request)
  387. )
  388. def subscriptions_renew(request, template="storefront/subscriptions_renewals.html"):
  389. def _render(request, form, userform, second_address_form, shipping_type):
  390. return render_to_response(
  391. template,
  392. {
  393. "form": form,
  394. "userform": userform,
  395. "second_address": second_address_form,
  396. "type": shipping_type,
  397. },
  398. context_instance=RequestContext(request),
  399. )
  400. # set some sane defaults
  401. user = request.user
  402. subscription_initial = {"duration": 1}
  403. primary_initial = {"region": "ME", "country": "US"}
  404. secondary_initial = {}
  405. shipping_type = get_type(None, "ME", "US")
  406. if user.is_authenticated():
  407. profile = get_profile(user)
  408. secondary_address = get_profile_secondary_address(user)
  409. shipping_type = get_type_by_profile(profile)
  410. primary_initial = model_to_dict(user)
  411. primary_initial.update(model_to_dict(profile))
  412. secondary_initial = model_to_dict(secondary_address)
  413. userform = ProfileUpdateForm(
  414. user, request.POST or None, initial=primary_initial, prefix="form2"
  415. )
  416. else:
  417. userform = ProfileCreateForm(
  418. request.POST or None, initial=primary_initial, prefix="form2"
  419. )
  420. subscription_form = forms.SubscriptionForm(
  421. request.POST or None,
  422. initial=subscription_initial,
  423. shipping_type=shipping_type,
  424. prefix="form1",
  425. use_account_number=True,
  426. renewal=True,
  427. )
  428. second_address_form = ProfileSecondaryAddressForm(
  429. request.POST or None, initial=secondary_initial, prefix="form3"
  430. )
  431. if (
  432. request.method == "POST"
  433. and userform.is_valid()
  434. and second_address_form.is_valid()
  435. ):
  436. # we've called is_valid for both the profile and address forms
  437. shipping_type = get_type(
  438. userform.cleaned_data.get("postal_code", None),
  439. userform.cleaned_data.get("region", None),
  440. userform.cleaned_data.get("country", None),
  441. postal_code2=second_address_form.cleaned_data.get("postal_code", None),
  442. region2=second_address_form.cleaned_data.get("region", None),
  443. country_code2=second_address_form.cleaned_data.get("country", None),
  444. )
  445. subscription_form = forms.SubscriptionForm(
  446. request.POST or None,
  447. shipping_type=shipping_type,
  448. initial=subscription_initial,
  449. prefix="form1",
  450. use_account_number=True,
  451. renewal=True,
  452. )
  453. if subscription_form.is_valid():
  454. user = userform.save(request=request)
  455. if not user.is_authenticated():
  456. login(request, user)
  457. second_address_form.save(user=user)
  458. subscription = subscription_form.save()
  459. account_number = subscription_form.cleaned_data["account_number"]
  460. remove_subscriptions(request)
  461. add_to_cart(
  462. request, subscription, account_number=account_number, quantity=1
  463. )
  464. return HttpResponseRedirect(reverse("checkout"))
  465. return _render(
  466. request, subscription_form, userform, second_address_form, shipping_type
  467. )