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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. from decimal import Decimal
  2. import datetime
  3. from django.utils import unittest
  4. from django.test.client import Client
  5. from oscar.apps.offer.models import *
  6. from oscar.apps.basket.models import Basket
  7. from oscar.apps.product.models import Item, ItemClass
  8. from oscar.apps.partner.models import Partner, StockRecord
  9. from oscar.test.helpers import create_product
  10. class RangeTest(unittest.TestCase):
  11. def setUp(self):
  12. self.prod = create_product()
  13. def test_all_products_range(self):
  14. range = Range.objects.create(name="All products", includes_all_products=True)
  15. self.assertTrue(range.contains_product(self.prod))
  16. def test_all_products_range_with_exception(self):
  17. range = Range.objects.create(name="All products", includes_all_products=True)
  18. range.excluded_products.add(self.prod)
  19. self.assertFalse(range.contains_product(self.prod))
  20. def test_empty_list(self):
  21. range = Range.objects.create(name="All products")
  22. self.assertFalse(range.contains_product(self.prod))
  23. def test_whitelisting(self):
  24. range = Range.objects.create(name="All products")
  25. range.included_products.add(self.prod)
  26. self.assertTrue(range.contains_product(self.prod))
  27. def test_blacklisting(self):
  28. range = Range.objects.create(name="All products", includes_all_products=True)
  29. range.excluded_products.add(self.prod)
  30. self.assertFalse(range.contains_product(self.prod))
  31. def test_included_classes(self):
  32. range = Range.objects.create(name="All products", includes_all_products=False)
  33. range.classes.add(self.prod.item_class)
  34. self.assertTrue(range.contains_product(self.prod))
  35. def test_included_class_with_exception(self):
  36. range = Range.objects.create(name="All products", includes_all_products=False)
  37. range.classes.add(self.prod.item_class)
  38. range.excluded_products.add(self.prod)
  39. self.assertFalse(range.contains_product(self.prod))
  40. class OfferTest(unittest.TestCase):
  41. def setUp(self):
  42. self.range = Range.objects.create(name="All products", includes_all_products=True)
  43. self.basket = Basket.objects.create()
  44. class CountConditionTest(OfferTest):
  45. def setUp(self):
  46. super(CountConditionTest, self).setUp()
  47. self.cond = CountCondition(range=self.range, type="Count", value=2)
  48. def test_empty_basket_fails_condition(self):
  49. self.assertFalse(self.cond.is_satisfied(self.basket))
  50. def test_matching_quantity_basket_passes_condition(self):
  51. self.basket.add_product(create_product(), 2)
  52. self.assertTrue(self.cond.is_satisfied(self.basket))
  53. def test_greater_quantity_basket_passes_condition(self):
  54. self.basket.add_product(create_product(), 3)
  55. self.assertTrue(self.cond.is_satisfied(self.basket))
  56. def test_consumption(self):
  57. self.basket.add_product(create_product(), 3)
  58. self.cond.consume_items(self.basket)
  59. self.assertEquals(1, self.basket.all_lines()[0].quantity_without_discount)
  60. class ValueConditionTest(OfferTest):
  61. def setUp(self):
  62. super(ValueConditionTest, self).setUp()
  63. self.cond = ValueCondition(range=self.range, type="Count", value=Decimal('10.00'))
  64. self.item = create_product(price=Decimal('5.00'))
  65. def test_empty_basket_fails_condition(self):
  66. self.assertFalse(self.cond.is_satisfied(self.basket))
  67. def test_less_value_basket_fails_condition(self):
  68. self.basket.add_product(self.item, 1)
  69. self.assertFalse(self.cond.is_satisfied(self.basket))
  70. def test_matching_basket_passes_condition(self):
  71. self.basket.add_product(self.item, 2)
  72. self.assertTrue(self.cond.is_satisfied(self.basket))
  73. def test_greater_than_basket_passes_condition(self):
  74. self.basket.add_product(self.item, 3)
  75. self.assertTrue(self.cond.is_satisfied(self.basket))
  76. def test_consumption(self):
  77. self.basket.add_product(self.item, 3)
  78. self.cond.consume_items(self.basket)
  79. self.assertEquals(1, self.basket.all_lines()[0].quantity_without_discount)
  80. class CoverageConditionTest(unittest.TestCase):
  81. def setUp(self):
  82. self.products = [create_product(Decimal('5.00')), create_product(Decimal('10.00'))]
  83. self.range = Range.objects.create(name="All products")
  84. for product in self.products:
  85. self.range.included_products.add(product)
  86. self.range.included_products.add(product)
  87. self.basket = Basket.objects.create()
  88. self.cond = CoverageCondition(range=self.range, type="Coverage", value=2)
  89. def test_empty_basket_fails(self):
  90. self.assertFalse(self.cond.is_satisfied(self.basket))
  91. def test_single_item_fails(self):
  92. self.basket.add_product(self.products[0])
  93. self.assertFalse(self.cond.is_satisfied(self.basket))
  94. def test_duplicate_item_fails(self):
  95. self.basket.add_product(self.products[0])
  96. self.basket.add_product(self.products[0])
  97. self.assertFalse(self.cond.is_satisfied(self.basket))
  98. def test_covering_items_pass(self):
  99. self.basket.add_product(self.products[0])
  100. self.basket.add_product(self.products[1])
  101. self.assertTrue(self.cond.is_satisfied(self.basket))
  102. def test_covering_items_are_consumed(self):
  103. self.basket.add_product(self.products[0])
  104. self.basket.add_product(self.products[1])
  105. self.cond.consume_items(self.basket)
  106. self.assertEquals(0, self.basket.num_items_without_discount)
  107. class PercentageDiscountBenefitTest(OfferTest):
  108. def setUp(self):
  109. super(PercentageDiscountBenefitTest, self).setUp()
  110. self.benefit = PercentageDiscountBenefit(range=self.range, type="PercentageDiscount", value=Decimal('15.00'))
  111. self.item = create_product(price=Decimal('5.00'))
  112. def test_no_discount_for_empty_basket(self):
  113. self.assertEquals(Decimal('0.00'), self.benefit.apply(self.basket))
  114. def test_discount_for_single_item_basket(self):
  115. self.basket.add_product(self.item, 1)
  116. self.assertEquals(Decimal('0.15') * Decimal('5.00'), self.benefit.apply(self.basket))
  117. def test_discount_for_multi_item_basket(self):
  118. self.basket.add_product(self.item, 3)
  119. self.assertEquals(Decimal('3') * Decimal('0.15') * Decimal('5.00'), self.benefit.apply(self.basket))
  120. def test_discount_for_multi_item_basket_with_max_affected_items_set(self):
  121. self.basket.add_product(self.item, 3)
  122. self.benefit.max_affected_items = 1
  123. self.assertEquals(Decimal('0.15') * Decimal('5.00'), self.benefit.apply(self.basket))
  124. def test_discount_can_only_be_applied_once(self):
  125. self.basket.add_product(self.item, 3)
  126. first_discount = self.benefit.apply(self.basket)
  127. second_discount = self.benefit.apply(self.basket)
  128. self.assertEquals(Decimal('0.00'), second_discount)
  129. def test_discount_can_be_applied_several_times_when_max_is_set(self):
  130. self.basket.add_product(self.item, 3)
  131. self.benefit.max_affected_items = 1
  132. for i in range(1, 4):
  133. self.assertTrue(self.benefit.apply(self.basket) > 0)
  134. class AbsoluteDiscountBenefitTest(OfferTest):
  135. def setUp(self):
  136. super(AbsoluteDiscountBenefitTest, self).setUp()
  137. self.benefit = AbsoluteDiscountBenefit(range=self.range, type="Absolute", value=Decimal('10.00'))
  138. self.item = create_product(price=Decimal('5.00'))
  139. def test_no_discount_for_empty_basket(self):
  140. self.assertEquals(Decimal('0.00'), self.benefit.apply(self.basket))
  141. def test_discount_for_single_item_basket(self):
  142. self.basket.add_product(self.item, 1)
  143. self.assertEquals(Decimal('5.00'), self.benefit.apply(self.basket))
  144. def test_discount_for_multi_item_basket(self):
  145. self.basket.add_product(self.item, 3)
  146. self.assertEquals(Decimal('10.00'), self.benefit.apply(self.basket))
  147. def test_discount_for_multi_item_basket_with_max_affected_items_set(self):
  148. self.basket.add_product(self.item, 3)
  149. self.benefit.max_affected_items = 1
  150. self.assertEquals(Decimal('5.00'), self.benefit.apply(self.basket))
  151. def test_discount_can_only_be_applied_once(self):
  152. # Add 3 items to make total 15.00
  153. self.basket.add_product(self.item, 3)
  154. first_discount = self.benefit.apply(self.basket)
  155. self.assertEquals(Decimal('10.00'), first_discount)
  156. second_discount = self.benefit.apply(self.basket)
  157. self.assertEquals(Decimal('5.00'), second_discount)
  158. class MultibuyDiscountBenefitTest(OfferTest):
  159. def setUp(self):
  160. super(MultibuyDiscountBenefitTest, self).setUp()
  161. self.benefit = MultibuyDiscountBenefit(range=self.range, type="Multibuy", value=1)
  162. self.item = create_product(price=Decimal('5.00'))
  163. def test_no_discount_for_empty_basket(self):
  164. self.assertEquals(Decimal('0.00'), self.benefit.apply(self.basket))
  165. def test_discount_for_single_item_basket(self):
  166. self.basket.add_product(self.item, 1)
  167. self.assertEquals(Decimal('5.00'), self.benefit.apply(self.basket))
  168. def test_discount_for_multi_item_basket(self):
  169. self.basket.add_product(self.item, 3)
  170. self.assertEquals(Decimal('5.00'), self.benefit.apply(self.basket))
  171. def test_discount_consumes_item(self):
  172. self.basket.add_product(self.item, 1)
  173. first_discount = self.benefit.apply(self.basket)
  174. self.assertEquals(Decimal('5.00'), first_discount)
  175. second_discount = self.benefit.apply(self.basket)
  176. self.assertEquals(Decimal('0.00'), second_discount)
  177. class FixedPriceBenefitTest(OfferTest):
  178. def setUp(self):
  179. super(FixedPriceBenefitTest, self).setUp()
  180. self.benefit = FixedPriceBenefit(range=self.range, type="FixedPrice", value=Decimal('10.00'))
  181. def test_correct_discount_is_returned(self):
  182. products = [create_product(Decimal('8.00')), create_product(Decimal('4.00'))]
  183. range = Range.objects.create(name="Dummy range")
  184. for product in products:
  185. range.included_products.add(product)
  186. range.included_products.add(product)
  187. basket = Basket.objects.create()
  188. [basket.add_product(p) for p in products]
  189. condition = CoverageCondition(range=range, type="Coverage", value=2)
  190. discount = self.benefit.apply(basket, condition)
  191. self.assertEquals(Decimal('2.00'), discount)
  192. def test_no_discount_is_returned_when_value_is_greater_than_product_total(self):
  193. products = [create_product(Decimal('4.00')), create_product(Decimal('4.00'))]
  194. range = Range.objects.create(name="Dummy range")
  195. for product in products:
  196. range.included_products.add(product)
  197. range.included_products.add(product)
  198. basket = Basket.objects.create()
  199. [basket.add_product(p) for p in products]
  200. condition = CoverageCondition(range=range, type="Coverage", value=2)
  201. discount = self.benefit.apply(basket, condition)
  202. self.assertEquals(Decimal('0.00'), discount)
  203. class ConditionalOfferTest(unittest.TestCase):
  204. def test_is_active(self):
  205. start = datetime.date(2011, 01, 01)
  206. test = datetime.date(2011, 01, 10)
  207. end = datetime.date(2011, 02, 01)
  208. offer = ConditionalOffer(start_date=start, end_date=end)
  209. self.assertTrue(offer.is_active(test))
  210. def test_is_inactive(self):
  211. start = datetime.date(2011, 01, 01)
  212. test = datetime.date(2011, 03, 10)
  213. end = datetime.date(2011, 02, 01)
  214. offer = ConditionalOffer(start_date=start, end_date=end)
  215. self.assertFalse(offer.is_active(test))
  216. class VoucherTest(unittest.TestCase):
  217. def test_is_active(self):
  218. start = datetime.date(2011, 01, 01)
  219. test = datetime.date(2011, 01, 10)
  220. end = datetime.date(2011, 02, 01)
  221. voucher = Voucher(start_date=start, end_date=end)
  222. self.assertTrue(voucher.is_active(test))
  223. def test_is_inactive(self):
  224. start = datetime.date(2011, 01, 01)
  225. test = datetime.date(2011, 03, 10)
  226. end = datetime.date(2011, 02, 01)
  227. voucher = Voucher(start_date=start, end_date=end)
  228. self.assertFalse(voucher.is_active(test))
  229. def test_codes_are_saved_as_uppercase(self):
  230. start = datetime.date(2011, 01, 01)
  231. end = datetime.date(2011, 02, 01)
  232. voucher = Voucher(name="Dummy voucher", code="lowercase", start_date=start, end_date=end)
  233. voucher.save()
  234. self.assertEquals("LOWERCASE", voucher.code)