Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

absolute_benefit_tests.py 13KB

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