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.

test_basket.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. import datetime
  2. from decimal import Decimal as D
  3. from http import client as http_client
  4. from http.cookies import _unquote
  5. from django.conf import settings
  6. from django.test import TestCase
  7. from django.urls import reverse
  8. from django.utils.translation import gettext
  9. from oscar.apps.basket import reports
  10. from oscar.apps.basket.models import Basket
  11. from oscar.apps.partner import strategy
  12. from oscar.core.compat import get_user_model
  13. from oscar.test import factories
  14. from oscar.test.basket import add_product
  15. from oscar.test.factories import create_product
  16. from oscar.test.testcases import WebTestCase
  17. User = get_user_model()
  18. class TestBasketMerging(TestCase):
  19. def setUp(self):
  20. self.product = create_product(num_in_stock=10)
  21. self.user_basket = Basket()
  22. self.user_basket.strategy = strategy.Default()
  23. add_product(self.user_basket, product=self.product)
  24. self.cookie_basket = Basket()
  25. self.cookie_basket.strategy = strategy.Default()
  26. add_product(self.cookie_basket, quantity=2, product=self.product)
  27. self.user_basket.merge(self.cookie_basket, add_quantities=False)
  28. def test_cookie_basket_has_status_set(self):
  29. self.assertEqual(Basket.MERGED, self.cookie_basket.status)
  30. def test_lines_are_moved_across(self):
  31. self.assertEqual(1, self.user_basket.lines.all().count())
  32. def test_merge_line_takes_max_quantity(self):
  33. line = self.user_basket.lines.get(product=self.product)
  34. self.assertEqual(2, line.quantity)
  35. class AnonAddToBasketViewTests(WebTestCase):
  36. csrf_checks = False
  37. def setUp(self):
  38. self.product = create_product(
  39. price=D('10.00'), num_in_stock=10)
  40. url = reverse('basket:add', kwargs={'pk': self.product.pk})
  41. post_params = {'product_id': self.product.id,
  42. 'action': 'add',
  43. 'quantity': 1}
  44. self.response = self.app.post(url, params=post_params)
  45. def test_cookie_is_created(self):
  46. self.assertTrue('oscar_open_basket' in self.response.test_app.cookies)
  47. def test_price_is_recorded(self):
  48. oscar_open_basket_cookie = _unquote(self.response.test_app.cookies['oscar_open_basket'])
  49. basket_id = oscar_open_basket_cookie.split(':')[0]
  50. basket = Basket.objects.get(id=basket_id)
  51. line = basket.lines.get(product=self.product)
  52. stockrecord = self.product.stockrecords.all()[0]
  53. self.assertEqual(stockrecord.price_excl_tax, line.price_excl_tax)
  54. class BasketSummaryViewTests(WebTestCase):
  55. def setUp(self):
  56. url = reverse('basket:summary')
  57. self.response = self.app.get(url)
  58. def test_shipping_method_in_context(self):
  59. self.assertTrue('shipping_method' in self.response.context)
  60. def test_order_total_in_context(self):
  61. self.assertTrue('order_total' in self.response.context)
  62. def test_view_does_not_error(self):
  63. self.assertEqual(http_client.OK, self.response.status_code)
  64. def test_basket_in_context(self):
  65. self.assertTrue('basket' in self.response.context)
  66. def test_basket_is_empty(self):
  67. basket = self.response.context['basket']
  68. self.assertEqual(0, basket.num_lines)
  69. class BasketThresholdTest(WebTestCase):
  70. csrf_checks = False
  71. def setUp(self):
  72. self._old_threshold = settings.OSCAR_MAX_BASKET_QUANTITY_THRESHOLD
  73. settings.OSCAR_MAX_BASKET_QUANTITY_THRESHOLD = 3
  74. def tearDown(self):
  75. settings.OSCAR_MAX_BASKET_QUANTITY_THRESHOLD = self._old_threshold
  76. def test_adding_more_than_threshold_raises(self):
  77. dummy_product = create_product(price=D('10.00'), num_in_stock=10)
  78. url = reverse('basket:add', kwargs={'pk': dummy_product.pk})
  79. post_params = {'product_id': dummy_product.id,
  80. 'action': 'add',
  81. 'quantity': 2}
  82. response = self.app.post(url, params=post_params)
  83. self.assertTrue('oscar_open_basket' in response.test_app.cookies)
  84. post_params = {'product_id': dummy_product.id,
  85. 'action': 'add',
  86. 'quantity': 2}
  87. response = self.app.post(url, params=post_params)
  88. expected = gettext(
  89. "Due to technical limitations we are not able to ship more "
  90. "than %(threshold)d items in one order. Your basket currently "
  91. "has %(basket)d items."
  92. ) % ({'threshold': 3, 'basket': 2})
  93. self.assertTrue(expected in response.test_app.cookies['messages'])
  94. class BasketReportTests(TestCase):
  95. def test_open_report_doesnt_error(self):
  96. data = {
  97. 'start_date': datetime.date(2012, 5, 1),
  98. 'end_date': datetime.date(2012, 5, 17),
  99. 'formatter': 'CSV'
  100. }
  101. generator = reports.OpenBasketReportGenerator(**data)
  102. generator.generate()
  103. def test_submitted_report_doesnt_error(self):
  104. data = {
  105. 'start_date': datetime.date(2012, 5, 1),
  106. 'end_date': datetime.date(2012, 5, 17),
  107. 'formatter': 'CSV'
  108. }
  109. generator = reports.SubmittedBasketReportGenerator(**data)
  110. generator.generate()
  111. class SavedBasketTests(WebTestCase):
  112. csrf_checks = False
  113. def test_moving_from_saved_basket(self):
  114. self.user = User.objects.create_user(username='test', password='pass',
  115. email='test@example.com')
  116. product = create_product(price=D('10.00'), num_in_stock=2)
  117. basket = factories.create_basket(empty=True)
  118. basket.owner = self.user
  119. basket.save()
  120. add_product(basket, product=product)
  121. saved_basket, created = Basket.saved.get_or_create(owner=self.user)
  122. saved_basket.strategy = basket.strategy
  123. add_product(saved_basket, product=product)
  124. response = self.get(reverse('basket:summary'))
  125. saved_formset = response.context['saved_formset']
  126. saved_form = saved_formset.forms[0]
  127. data = {
  128. saved_formset.add_prefix('INITIAL_FORMS'): 1,
  129. saved_formset.add_prefix('MAX_NUM_FORMS'): 1,
  130. saved_formset.add_prefix('TOTAL_FORMS'): 1,
  131. saved_form.add_prefix('id'): saved_form.initial['id'],
  132. saved_form.add_prefix('move_to_basket'): True,
  133. }
  134. response = self.post(reverse('basket:saved'), params=data)
  135. self.assertEqual(Basket.open.get(id=basket.id).lines.get(
  136. product=product).quantity, 2)
  137. self.assertRedirects(response, reverse('basket:summary'))
  138. def test_moving_from_saved_basket_more_than_stocklevel_raises(self):
  139. self.user = User.objects.create_user(username='test', password='pass',
  140. email='test@example.com')
  141. product = create_product(price=D('10.00'), num_in_stock=1)
  142. basket, created = Basket.open.get_or_create(owner=self.user)
  143. add_product(basket, product=product)
  144. saved_basket, created = Basket.saved.get_or_create(owner=self.user)
  145. add_product(saved_basket, product=product)
  146. response = self.get(reverse('basket:summary'))
  147. saved_formset = response.context['saved_formset']
  148. saved_form = saved_formset.forms[0]
  149. data = {
  150. saved_formset.add_prefix('INITIAL_FORMS'): 1,
  151. saved_formset.add_prefix('MAX_NUM_FORMS'): 1,
  152. saved_formset.add_prefix('TOTAL_FORMS'): 1,
  153. saved_form.add_prefix('id'): saved_form.initial['id'],
  154. saved_form.add_prefix('move_to_basket'): True,
  155. }
  156. response = self.post(reverse('basket:saved'), params=data)
  157. # we can't add more than stock level into basket
  158. self.assertEqual(Basket.open.get(id=basket.id).lines.get(product=product).quantity, 1)
  159. self.assertRedirects(response, reverse('basket:summary'))
  160. class BasketFormSetTests(WebTestCase):
  161. csrf_checks = False
  162. def test_formset_with_removed_line(self):
  163. products = [create_product() for i in range(3)]
  164. basket = factories.create_basket(empty=True)
  165. basket.owner = self.user
  166. basket.save()
  167. add_product(basket, product=products[0])
  168. add_product(basket, product=products[1])
  169. add_product(basket, product=products[2])
  170. response = self.get(reverse('basket:summary'))
  171. formset = response.context['formset']
  172. self.assertEqual(len(formset.forms), 3)
  173. basket.lines.filter(product=products[0]).delete()
  174. management_form = formset.management_form
  175. data = {
  176. formset.add_prefix('INITIAL_FORMS'): management_form.initial['INITIAL_FORMS'],
  177. formset.add_prefix('MAX_NUM_FORMS'): management_form.initial['MAX_NUM_FORMS'],
  178. formset.add_prefix('TOTAL_FORMS'): management_form.initial['TOTAL_FORMS'],
  179. 'form-0-quantity': 1,
  180. 'form-0-id': formset.forms[0].instance.id,
  181. 'form-1-quantity': 2,
  182. 'form-1-id': formset.forms[1].instance.id,
  183. 'form-2-quantity': 2,
  184. 'form-2-id': formset.forms[2].instance.id,
  185. }
  186. response = self.post(reverse('basket:summary'), params=data)
  187. self.assertEqual(response.status_code, 302)
  188. formset = response.follow().context['formset']
  189. self.assertEqual(len(formset.forms), 2)
  190. self.assertEqual(len(formset.forms_with_instances), 2)
  191. self.assertEqual(basket.lines.all()[0].quantity, 2)
  192. self.assertEqual(basket.lines.all()[1].quantity, 2)
  193. def test_invalid_formset_with_removed_line(self):
  194. products = [create_product() for i in range(3)]
  195. basket = factories.create_basket(empty=True)
  196. basket.owner = self.user
  197. basket.save()
  198. add_product(basket, product=products[0])
  199. add_product(basket, product=products[1])
  200. add_product(basket, product=products[2])
  201. response = self.get(reverse('basket:summary'))
  202. formset = response.context['formset']
  203. self.assertEqual(len(formset.forms), 3)
  204. basket.lines.filter(product=products[0]).delete()
  205. stockrecord = products[1].stockrecords.first()
  206. stockrecord.num_in_stock = 0
  207. stockrecord.save()
  208. management_form = formset.management_form
  209. data = {
  210. formset.add_prefix('INITIAL_FORMS'): management_form.initial['INITIAL_FORMS'],
  211. formset.add_prefix('MAX_NUM_FORMS'): management_form.initial['MAX_NUM_FORMS'],
  212. formset.add_prefix('TOTAL_FORMS'): management_form.initial['TOTAL_FORMS'],
  213. 'form-0-quantity': 1,
  214. 'form-0-id': formset.forms[0].instance.id,
  215. 'form-1-quantity': 2,
  216. 'form-1-id': formset.forms[1].instance.id,
  217. 'form-2-quantity': 2,
  218. 'form-2-id': formset.forms[2].instance.id,
  219. }
  220. response = self.post(reverse('basket:summary'), params=data)
  221. self.assertEqual(response.status_code, 200)
  222. formset = response.context['formset']
  223. self.assertEqual(len(formset.forms), 3)
  224. self.assertEqual(len(formset.forms_with_instances), 2)
  225. self.assertEqual(basket.lines.all()[0].quantity, 1)
  226. self.assertEqual(basket.lines.all()[1].quantity, 1)