You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import re
  2. from django.http import HttpResponseRedirect
  3. from django.shortcuts import get_object_or_404
  4. from django.core.urlresolvers import reverse
  5. from django.contrib import messages
  6. from django.core.exceptions import ObjectDoesNotExist
  7. from django.template.response import TemplateResponse
  8. from oscar.view.generic import ModelView
  9. from oscar.core.loading import import_module
  10. import_module('basket.models', ['Basket', 'Line', 'InvalidBasketLineError'], locals())
  11. import_module('basket.forms', ['FormFactory'], locals())
  12. import_module('basket.signals', ['basket_addition'], locals())
  13. import_module('product.models', ['Item'], locals())
  14. import_module('offer.models', ['Voucher'], locals())
  15. class BasketView(ModelView):
  16. u"""Class-based view for the basket model."""
  17. template_file = 'oscar/basket/summary.html'
  18. def __init__(self):
  19. self.response = HttpResponseRedirect(reverse('oscar-basket'))
  20. def get_model(self):
  21. u"""Return a basket model"""
  22. return self.request.basket
  23. def handle_GET(self, basket):
  24. u"""Handle GET requests against the basket"""
  25. saved_basket = None
  26. if self.request.user.is_authenticated():
  27. try:
  28. saved_basket = Basket.saved.get(owner=self.request.user)
  29. except Basket.DoesNotExist:
  30. saved_basket = None
  31. self.response = TemplateResponse(self.request, self.template_file, {'basket': basket,
  32. 'saved_basket': saved_basket})
  33. def handle_POST(self, basket):
  34. u"""Handle POST requests against the basket"""
  35. try:
  36. super(BasketView, self).handle_POST(basket)
  37. except InvalidBasketLineError, e:
  38. # We handle InvalidBasketLineError gracefully as it will be domain logic
  39. # which causes this to be thrown (eg. a product out of stock)
  40. messages.error(self.request, str(e))
  41. def do_flush(self, basket):
  42. u"""Flush basket content"""
  43. basket.flush()
  44. messages.info(self.request, "Your basket has been emptied")
  45. def do_add(self, basket):
  46. u"""Add an item to the basket"""
  47. item = get_object_or_404(Item.objects, pk=self.request.POST['product_id'])
  48. # Send signal so analytics can track this event. Note that be emitting
  49. # the signal here, we do not track quantity changes to a product - only
  50. # the initial "add".
  51. basket_addition.send(sender=self, product=item, user=self.request.user)
  52. factory = FormFactory()
  53. form = factory.create(item, self.request.POST)
  54. if not form.is_valid():
  55. print form.errors
  56. self.response = HttpResponseRedirect(item.get_absolute_url())
  57. messages.error(self.request, "Unable to add your item to the basket - submission not valid")
  58. else:
  59. # Extract product options from POST
  60. options = []
  61. for option in item.options:
  62. if option.code in form.cleaned_data:
  63. options.append({'option': option, 'value': form.cleaned_data[option.code]})
  64. basket.add_product(item, form.cleaned_data['quantity'], options)
  65. messages.info(self.request, "'%s' (quantity %d) has been added to your basket" %
  66. (item.get_title(), form.cleaned_data['quantity']))
  67. def do_add_voucher(self, basket):
  68. code = self.request.POST['voucher_code']
  69. # First check if the voucher is already in the basket
  70. try:
  71. voucher = basket.vouchers.get(code=code)
  72. messages.error(self.request, "You have already added the '%s' voucher to your basket" % voucher.code)
  73. return
  74. except ObjectDoesNotExist:
  75. pass
  76. try:
  77. voucher = Voucher._default_manager.get(code=code)
  78. if not voucher.is_active():
  79. messages.error(self.request, "The '%s' voucher has expired" % voucher.code)
  80. return
  81. is_available, message = voucher.is_available_to_user(self.request.user)
  82. if not is_available:
  83. messages.error(self.request, message)
  84. return
  85. basket.vouchers.add(voucher)
  86. basket.save()
  87. messages.info(self.request, "Voucher '%s' added to basket" % voucher.code)
  88. except ObjectDoesNotExist:
  89. messages.error(self.request, "No voucher found with code '%s'" % code)
  90. def do_remove_voucher(self, basket):
  91. code = self.request.POST['voucher_code']
  92. try:
  93. voucher = basket.vouchers.get(code=code)
  94. basket.vouchers.remove(voucher)
  95. basket.save()
  96. messages.info(self.request, "Voucher '%s' removed from basket" % voucher.code)
  97. except ObjectDoesNotExist:
  98. messages.error(self.request, "No voucher found with code '%s'" % code)
  99. def do_bulk_load(self, basket):
  100. num_additions = 0
  101. num_not_found = 0
  102. for sku in re.findall(r"[\d -]{5,}", self.request.POST['source_text']):
  103. try:
  104. item = Item.objects.get(upc=sku)
  105. basket.add_product(item)
  106. num_additions += 1
  107. except Item.DoesNotExist:
  108. num_not_found += 1
  109. messages.info(self.request, "Added %d items to your basket (%d missing)" % (num_additions, num_not_found))
  110. class LineView(ModelView):
  111. def __init__(self):
  112. self.response = HttpResponseRedirect(reverse('oscar-basket'))
  113. def get_model(self):
  114. """
  115. Returns the basket line in question
  116. """
  117. return self.request.basket.lines.get(line_reference=self.kwargs['line_reference'])
  118. def handle_POST(self, line):
  119. u"""Handle POST requests against the basket line"""
  120. try:
  121. super(LineView, self).handle_POST(line)
  122. except Basket.DoesNotExist:
  123. messages.error(self.request, "You don't have a basket to adjust the lines of")
  124. except Line.DoesNotExist:
  125. messages.error(self.request, "Unable to find a line with reference %s in your basket" % self.kwargs['line_reference'])
  126. except InvalidBasketLineError, e:
  127. messages.error(self.request, str(e))
  128. def _get_quantity(self):
  129. u"""Get item quantity"""
  130. if 'quantity' in self.request.POST:
  131. return int(self.request.POST['quantity'])
  132. return 0
  133. def do_increment_quantity(self, line):
  134. u"""Increment item quantity"""
  135. q = self._get_quantity()
  136. line.quantity += q
  137. line.save()
  138. msg = "The quantity of '%s' has been increased by %d" % (line.product, q)
  139. messages.info(self.request, msg)
  140. def do_decrement_quantity(self, line):
  141. u"""Decrement item quantity"""
  142. q = self._get_quantity()
  143. line.quantity -= q
  144. line.save()
  145. msg = "The quantity of '%s' has been decreased by %d" % (line.product, q)
  146. messages.info(self.request, msg)
  147. def do_set_quantity(self, line):
  148. u"""Set an item quantity"""
  149. q = self._get_quantity()
  150. line.quantity = q
  151. line.save()
  152. msg = "The quantity of '%s' has been set to %d" % (line.product, q)
  153. messages.info(self.request, msg)
  154. def do_delete(self, line):
  155. u"""Delete a basket item"""
  156. line.delete()
  157. msg = "'%s' has been removed from your basket" % line.product
  158. messages.info(self.request, msg)
  159. def do_save_for_later(self, line):
  160. u"""Save basket for later use"""
  161. if not self.request.user.is_authenticated():
  162. messages.error(self.request, "Only signed in users can save basket lines")
  163. return
  164. saved_basket, _ = Basket.saved.get_or_create(owner=self.request.user)
  165. saved_basket.merge_line(line)
  166. msg = "'%s' has been saved for later" % line.product
  167. messages.info(self.request, msg)
  168. class SavedLineView(ModelView):
  169. def __init__(self):
  170. self.response = HttpResponseRedirect(reverse('oscar-basket'))
  171. def get_model(self):
  172. basket = Basket.saved.get(owner=self.request.user)
  173. return basket.lines.get(line_reference=self.kwargs['line_reference'])
  174. def handle_POST(self, line):
  175. u"""Handle POST requests against a saved line"""
  176. try:
  177. super(SavedLineView, self).handle_POST(line)
  178. except InvalidBasketLineError, e:
  179. messages.error(self.request, str(e))
  180. def do_move_to_basket(self, line):
  181. u"""Merge line items in to current basket"""
  182. real_basket = self.request.basket
  183. real_basket.merge_line(line)
  184. msg = "'%s' has been moved back to your basket" % line.product
  185. messages.info(self.request, msg)
  186. def do_delete(self, line):
  187. u"""Delete line item"""
  188. line.delete()
  189. msg = "'%s' has been removed" % line.product
  190. messages.warn(self.request, msg)
  191. def _get_quantity(self):
  192. u"""Get line item quantity"""
  193. if 'quantity' in self.request.POST:
  194. return int(self.request.POST['quantity'])
  195. return 0