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.

absolute_benefit_tests.py 14KB

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