Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

absolute_benefit_tests.py 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. from decimal import Decimal as D
  2. from django.core import exceptions
  3. from django.test import TestCase
  4. import mock
  5. from oscar.apps.offer import models
  6. from oscar.test.basket import add_product, add_products
  7. from oscar.test import factories
  8. class TestAnAbsoluteDiscountAppliedWithCountCondition(TestCase):
  9. def setUp(self):
  10. range = models.Range.objects.create(
  11. name="All products", includes_all_products=True)
  12. self.condition = models.CountCondition.objects.create(
  13. range=range,
  14. type=models.Condition.COUNT,
  15. value=2)
  16. self.offer = mock.Mock()
  17. self.offer.applies_to_tax_exclusive_prices = False
  18. self.benefit = models.AbsoluteDiscountBenefit.objects.create(
  19. range=range,
  20. type=models.Benefit.FIXED,
  21. value=D('3.00'))
  22. self.basket = factories.create_basket(empty=True)
  23. def test_applies_correctly_to_empty_basket(self):
  24. result = self.benefit.apply(self.basket, self.condition, self.offer)
  25. self.assertEqual(D('0.00'), result.discount)
  26. self.assertEqual(0, self.basket.num_items_with_discount)
  27. self.assertEqual(0, self.basket.num_items_without_discount)
  28. def test_applies_correctly_to_basket_which_matches_condition_with_one_line(self):
  29. add_product(self.basket, price=D('12.00'), quantity=2)
  30. result = self.benefit.apply(self.basket, self.condition, self.offer)
  31. self.assertEqual(D('3.00'), result.discount)
  32. self.assertEqual(2, self.basket.num_items_with_discount)
  33. self.assertEqual(0, self.basket.num_items_without_discount)
  34. # Check the discount is applied equally to each item in the line
  35. line = self.basket.all_lines()[0]
  36. prices = line.get_price_breakdown()
  37. self.assertEqual(1, len(prices))
  38. self.assertEqual(D('10.50'), prices[0][0])
  39. def test_applies_correctly_to_basket_which_matches_condition_with_multiple_lines(self):
  40. # Use a basket with 2 lines
  41. add_products(self.basket, [
  42. (D('12.00'), 1), (D('12.00'), 1)])
  43. result = self.benefit.apply(self.basket, self.condition, self.offer)
  44. self.assertTrue(result.is_successful)
  45. self.assertFalse(result.is_final)
  46. self.assertEqual(D('3.00'), result.discount)
  47. self.assertEqual(2, self.basket.num_items_with_discount)
  48. self.assertEqual(0, self.basket.num_items_without_discount)
  49. # Check the discount is applied equally to each line
  50. for line in self.basket.all_lines():
  51. self.assertEqual(D('1.50'), line.discount_value)
  52. def test_applies_correctly_to_basket_which_matches_condition_with_multiple_lines_and_lower_total_value(self):
  53. # Use a basket with 2 lines
  54. add_products(self.basket, [
  55. (D('1.00'), 1), (D('1.50'), 1)])
  56. result = self.benefit.apply(self.basket, self.condition, self.offer)
  57. self.assertTrue(result.is_successful)
  58. self.assertFalse(result.is_final)
  59. self.assertEqual(D('2.50'), result.discount)
  60. self.assertEqual(2, self.basket.num_items_with_discount)
  61. self.assertEqual(0, self.basket.num_items_without_discount)
  62. def test_applies_correctly_to_basket_which_exceeds_condition(self):
  63. add_products(self.basket, [
  64. (D('12.00'), 2), (D('10.00'), 2)])
  65. result = self.benefit.apply(self.basket, self.condition, self.offer)
  66. self.assertEqual(D('3.00'), result.discount)
  67. self.assertEqual(4, self.basket.num_items_with_discount)
  68. self.assertEqual(0, self.basket.num_items_without_discount)
  69. def test_applies_correctly_to_basket_which_exceeds_condition_with_smaller_prices_than_discount(self):
  70. add_products(self.basket, [
  71. (D('2.00'), 2), (D('4.00'), 2)])
  72. result = self.benefit.apply(self.basket, self.condition, self.offer)
  73. self.assertEqual(D('3.00'), result.discount)
  74. self.assertEqual(4, self.basket.num_items_with_discount)
  75. self.assertEqual(0, self.basket.num_items_without_discount)
  76. def test_applies_correctly_to_basket_which_exceeds_condition_with_smaller_prices_than_discount_and_higher_prices_first(self):
  77. add_products(self.basket, [
  78. (D('2.00'), 2), (D('4.00'), 2)])
  79. result = self.benefit.apply(self.basket, self.condition, self.offer)
  80. self.assertEqual(D('3.00'), result.discount)
  81. self.assertEqual(4, self.basket.num_items_with_discount)
  82. self.assertEqual(0, self.basket.num_items_without_discount)
  83. class TestAnAbsoluteDiscount(TestCase):
  84. def setUp(self):
  85. range = models.Range.objects.create(
  86. name="All products", includes_all_products=True)
  87. self.condition = models.CountCondition.objects.create(
  88. range=range,
  89. type=models.Condition.COUNT,
  90. value=2)
  91. self.benefit = models.AbsoluteDiscountBenefit.objects.create(
  92. range=range,
  93. type=models.Benefit.FIXED,
  94. value=D('4.00'))
  95. self.offer = mock.Mock()
  96. self.offer.applies_to_tax_exclusive_prices = False
  97. self.basket = factories.create_basket(empty=True)
  98. def test_applies_correctly_when_discounts_need_rounding(self):
  99. # Split discount across 3 lines
  100. for price in [D('2.00'), D('2.00'), D('2.00')]:
  101. add_product(self.basket, price)
  102. result = self.benefit.apply(self.basket, self.condition, self.offer)
  103. self.assertEqual(D('4.00'), result.discount)
  104. # Check the discount is applied equally to each line
  105. line_discounts = [line.discount_value for line in self.basket.all_lines()]
  106. self.assertEqual(len(line_discounts), 3)
  107. for i, v in enumerate([D('1.33'), D('1.33'), D('1.34')]):
  108. self.assertEqual(line_discounts[i], v)
  109. class TestAnAbsoluteDiscountWithMaxItemsSetAppliedWithCountCondition(TestCase):
  110. def setUp(self):
  111. range = models.Range.objects.create(
  112. name="All products", includes_all_products=True)
  113. self.condition = models.CountCondition.objects.create(
  114. range=range,
  115. type=models.Condition.COUNT,
  116. value=2)
  117. self.benefit = models.AbsoluteDiscountBenefit.objects.create(
  118. range=range,
  119. type=models.Benefit.FIXED,
  120. value=D('3.00'),
  121. max_affected_items=1)
  122. self.offer = mock.Mock()
  123. self.offer.applies_to_tax_exclusive_prices = False
  124. self.basket = factories.create_basket(empty=True)
  125. def test_applies_correctly_to_empty_basket(self):
  126. result = self.benefit.apply(self.basket, self.condition, self.offer)
  127. self.assertEqual(D('0.00'), result.discount)
  128. self.assertEqual(0, self.basket.num_items_with_discount)
  129. self.assertEqual(0, self.basket.num_items_without_discount)
  130. def test_applies_correctly_to_basket_which_matches_condition(self):
  131. add_product(self.basket, D('12.00'), 2)
  132. result = self.benefit.apply(self.basket, self.condition, self.offer)
  133. self.assertEqual(D('3.00'), result.discount)
  134. self.assertEqual(2, self.basket.num_items_with_discount)
  135. self.assertEqual(0, self.basket.num_items_without_discount)
  136. def test_applies_correctly_to_basket_which_exceeds_condition(self):
  137. add_products(self.basket, [(D('12.00'), 2), (D('10.00'), 2)])
  138. result = self.benefit.apply(self.basket, self.condition, self.offer)
  139. self.assertEqual(D('3.00'), result.discount)
  140. self.assertEqual(2, self.basket.num_items_with_discount)
  141. self.assertEqual(2, self.basket.num_items_without_discount)
  142. def test_applies_correctly_to_basket_which_exceeds_condition_but_with_smaller_prices_than_discount(self):
  143. add_products(self.basket, [(D('2.00'), 2), (D('1.00'), 2)])
  144. result = self.benefit.apply(self.basket, self.condition, self.offer)
  145. self.assertEqual(D('1.00'), result.discount)
  146. self.assertEqual(2, self.basket.num_items_with_discount)
  147. self.assertEqual(2, self.basket.num_items_without_discount)
  148. class TestAnAbsoluteDiscountAppliedWithValueCondition(TestCase):
  149. def setUp(self):
  150. range = models.Range.objects.create(
  151. name="All products", includes_all_products=True)
  152. self.condition = models.ValueCondition.objects.create(
  153. range=range,
  154. type=models.Condition.VALUE,
  155. value=D('10.00'))
  156. self.benefit = models.AbsoluteDiscountBenefit.objects.create(
  157. range=range,
  158. type=models.Benefit.FIXED,
  159. value=D('3.00'))
  160. self.offer = mock.Mock()
  161. self.offer.applies_to_tax_exclusive_prices = False
  162. self.basket = factories.create_basket(empty=True)
  163. def test_applies_correctly_to_empty_basket(self):
  164. result = self.benefit.apply(self.basket, self.condition, self.offer)
  165. self.assertEqual(D('0.00'), result.discount)
  166. self.assertEqual(0, self.basket.num_items_with_discount)
  167. self.assertEqual(0, self.basket.num_items_without_discount)
  168. def test_applies_correctly_to_single_item_basket_which_matches_condition(self):
  169. add_products(self.basket, [(D('10.00'), 1)])
  170. result = self.benefit.apply(self.basket, self.condition, self.offer)
  171. self.assertEqual(D('3.00'), result.discount)
  172. self.assertEqual(1, self.basket.num_items_with_discount)
  173. self.assertEqual(0, self.basket.num_items_without_discount)
  174. def test_applies_correctly_to_multi_item_basket_which_matches_condition(self):
  175. add_products(self.basket, [(D('5.00'), 2)])
  176. result = self.benefit.apply(self.basket, self.condition, self.offer)
  177. self.assertEqual(D('3.00'), result.discount)
  178. self.assertEqual(2, self.basket.num_items_with_discount)
  179. self.assertEqual(0, self.basket.num_items_without_discount)
  180. def test_applies_correctly_to_multi_item_basket_which_exceeds_condition(self):
  181. add_products(self.basket, [(D('4.00'), 3)])
  182. result = self.benefit.apply(self.basket, self.condition, self.offer)
  183. self.assertEqual(D('3.00'), result.discount)
  184. self.assertEqual(3, self.basket.num_items_with_discount)
  185. self.assertEqual(0, self.basket.num_items_without_discount)
  186. def test_applies_correctly_to_multi_item_basket_which_exceeds_condition_but_matches_boundary(self):
  187. add_products(self.basket, [(D('5.00'), 3)])
  188. result = self.benefit.apply(self.basket, self.condition, self.offer)
  189. self.assertEqual(D('3.00'), result.discount)
  190. self.assertEqual(3, self.basket.num_items_with_discount)
  191. self.assertEqual(0, self.basket.num_items_without_discount)
  192. class TestAnAbsoluteDiscountWithMaxItemsSetAppliedWithValueCondition(TestCase):
  193. def setUp(self):
  194. range = models.Range.objects.create(
  195. name="All products", includes_all_products=True)
  196. self.condition = models.ValueCondition.objects.create(
  197. range=range,
  198. type=models.Condition.VALUE,
  199. value=D('10.00'))
  200. self.benefit = models.AbsoluteDiscountBenefit.objects.create(
  201. range=range,
  202. type=models.Benefit.FIXED,
  203. value=D('3.00'),
  204. max_affected_items=1)
  205. self.offer = mock.Mock()
  206. self.offer.applies_to_tax_exclusive_prices = False
  207. self.basket = factories.create_basket(empty=True)
  208. def test_applies_correctly_to_empty_basket(self):
  209. result = self.benefit.apply(self.basket, self.condition, self.offer)
  210. self.assertEqual(D('0.00'), result.discount)
  211. self.assertEqual(0, self.basket.num_items_with_discount)
  212. self.assertEqual(0, self.basket.num_items_without_discount)
  213. def test_applies_correctly_to_single_item_basket_which_matches_condition(self):
  214. add_products(self.basket, [(D('10.00'), 1)])
  215. result = self.benefit.apply(self.basket, self.condition, self.offer)
  216. self.assertEqual(D('3.00'), result.discount)
  217. self.assertEqual(1, self.basket.num_items_with_discount)
  218. self.assertEqual(0, self.basket.num_items_without_discount)
  219. def test_applies_correctly_to_multi_item_basket_which_matches_condition(self):
  220. add_products(self.basket, [(D('5.00'), 2)])
  221. result = self.benefit.apply(self.basket, self.condition, self.offer)
  222. self.assertEqual(D('3.00'), result.discount)
  223. self.assertEqual(2, self.basket.num_items_with_discount)
  224. self.assertEqual(0, self.basket.num_items_without_discount)
  225. def test_applies_correctly_to_multi_item_basket_which_exceeds_condition(self):
  226. add_products(self.basket, [(D('4.00'), 3)])
  227. result = self.benefit.apply(self.basket, self.condition, self.offer)
  228. self.assertEqual(D('3.00'), result.discount)
  229. self.assertEqual(3, self.basket.num_items_with_discount)
  230. self.assertEqual(0, self.basket.num_items_without_discount)
  231. def test_applies_correctly_to_multi_item_basket_which_exceeds_condition_but_matches_boundary(self):
  232. add_products(self.basket, [(D('5.00'), 3)])
  233. result = self.benefit.apply(self.basket, self.condition, self.offer)
  234. self.assertEqual(D('3.00'), result.discount)
  235. self.assertEqual(2, self.basket.num_items_with_discount)
  236. self.assertEqual(1, self.basket.num_items_without_discount)
  237. def test_applies_correctly_to_multi_item_basket_which_matches_condition_but_with_lower_prices_than_discount(self):
  238. add_products(self.basket, [(D('2.00'), 6)])
  239. result = self.benefit.apply(self.basket, self.condition, self.offer)
  240. self.assertEqual(D('2.00'), result.discount)
  241. self.assertEqual(5, self.basket.num_items_with_discount)
  242. self.assertEqual(1, self.basket.num_items_without_discount)
  243. class TestAnAbsoluteDiscountBenefit(TestCase):
  244. def test_requires_a_benefit_value(self):
  245. rng = models.Range.objects.create(
  246. name="", includes_all_products=True)
  247. benefit = models.Benefit.objects.create(
  248. type=models.Benefit.FIXED, range=rng
  249. )
  250. with self.assertRaises(exceptions.ValidationError):
  251. benefit.clean()