/tests/unit/offer/condition_tests.py

https://github.com/anthony-tresontani/django-oscar · Python · 215 lines · 161 code · 52 blank · 2 comment · 3 complexity · 6ab4a6baa640fa5f11bfeb66b33c67b7 MD5 · raw file

  1. from decimal import Decimal
  2. from django.test import TestCase
  3. from oscar.apps.offer import models
  4. from oscar.apps.basket.models import Basket
  5. from oscar.test.helpers import create_product
  6. from tests.unit.offer import OfferTest
  7. class CountConditionTest(OfferTest):
  8. def setUp(self):
  9. super(CountConditionTest, self).setUp()
  10. self.cond = models.CountCondition(range=self.range, type="Count", value=2)
  11. def test_empty_basket_fails_condition(self):
  12. self.assertFalse(self.cond.is_satisfied(self.basket))
  13. def test_not_discountable_product_fails_condition(self):
  14. prod1, prod2 = create_product(), create_product()
  15. prod2.is_discountable = False
  16. prod2.save()
  17. self.basket.add_product(prod1)
  18. self.basket.add_product(prod2)
  19. self.assertFalse(self.cond.is_satisfied(self.basket))
  20. def test_empty_basket_fails_partial_condition(self):
  21. self.assertFalse(self.cond.is_partially_satisfied(self.basket))
  22. def test_smaller_quantity_basket_passes_partial_condition(self):
  23. self.basket.add_product(create_product(), 1)
  24. self.assertTrue(self.cond.is_partially_satisfied(self.basket))
  25. def test_smaller_quantity_basket_upsell_message(self):
  26. self.basket.add_product(create_product(), 1)
  27. self.assertTrue('Buy 1 more product from ' in
  28. self.cond.get_upsell_message(self.basket))
  29. def test_matching_quantity_basket_fails_partial_condition(self):
  30. self.basket.add_product(create_product(), 2)
  31. self.assertFalse(self.cond.is_partially_satisfied(self.basket))
  32. def test_matching_quantity_basket_passes_condition(self):
  33. self.basket.add_product(create_product(), 2)
  34. self.assertTrue(self.cond.is_satisfied(self.basket))
  35. def test_greater_quantity_basket_passes_condition(self):
  36. self.basket.add_product(create_product(), 3)
  37. self.assertTrue(self.cond.is_satisfied(self.basket))
  38. def test_consumption(self):
  39. self.basket.add_product(create_product(), 3)
  40. self.cond.consume_items(self.basket)
  41. self.assertEquals(1, self.basket.all_lines()[0].quantity_without_discount)
  42. def test_is_satisfied_accounts_for_consumed_items(self):
  43. self.basket.add_product(create_product(), 3)
  44. self.cond.consume_items(self.basket)
  45. self.assertFalse(self.cond.is_satisfied(self.basket))
  46. def test_count_condition_is_applied_multpile_times(self):
  47. benefit = models.AbsoluteDiscountBenefit(range=self.range, type="Absolute", value=Decimal('10.00'))
  48. for i in range(10):
  49. self.basket.add_product(create_product(price=Decimal('5.00'), upc='upc_%i' % i), 1)
  50. product_range = models.Range.objects.create(name="All products", includes_all_products=True)
  51. condition = models.CountCondition(range=product_range, type="Count", value=2)
  52. first_discount = benefit.apply(self.basket, condition=condition)
  53. self.assertEquals(Decimal('10.00'), first_discount)
  54. second_discount = benefit.apply(self.basket, condition=condition)
  55. self.assertEquals(Decimal('10.00'), second_discount)
  56. class ValueConditionTest(OfferTest):
  57. def setUp(self):
  58. super(ValueConditionTest, self).setUp()
  59. self.cond = models.ValueCondition(range=self.range, type="Value", value=Decimal('10.00'))
  60. self.item = create_product(price=Decimal('5.00'))
  61. self.expensive_item = create_product(price=Decimal('15.00'))
  62. def test_empty_basket_fails_condition(self):
  63. self.assertFalse(self.cond.is_satisfied(self.basket))
  64. def test_empty_basket_fails_partial_condition(self):
  65. self.assertFalse(self.cond.is_partially_satisfied(self.basket))
  66. def test_less_value_basket_fails_condition(self):
  67. self.basket.add_product(self.item, 1)
  68. self.assertFalse(self.cond.is_satisfied(self.basket))
  69. def test_not_discountable_item_fails_condition(self):
  70. self.expensive_item.is_discountable = False
  71. self.expensive_item.save()
  72. self.basket.add_product(self.expensive_item, 1)
  73. self.assertFalse(self.cond.is_satisfied(self.basket))
  74. def test_upsell_message(self):
  75. self.basket.add_product(self.item, 1)
  76. self.assertTrue('Spend' in self.cond.get_upsell_message(self.basket))
  77. def test_matching_basket_fails_partial_condition(self):
  78. self.basket.add_product(self.item, 2)
  79. self.assertFalse(self.cond.is_partially_satisfied(self.basket))
  80. def test_less_value_basket_passes_partial_condition(self):
  81. self.basket.add_product(self.item, 1)
  82. self.assertTrue(self.cond.is_partially_satisfied(self.basket))
  83. def test_matching_basket_passes_condition(self):
  84. self.basket.add_product(self.item, 2)
  85. self.assertTrue(self.cond.is_satisfied(self.basket))
  86. def test_greater_than_basket_passes_condition(self):
  87. self.basket.add_product(self.item, 3)
  88. self.assertTrue(self.cond.is_satisfied(self.basket))
  89. def test_consumption(self):
  90. self.basket.add_product(self.item, 3)
  91. self.cond.consume_items(self.basket)
  92. self.assertEquals(1, self.basket.all_lines()[0].quantity_without_discount)
  93. def test_consumption_with_high_value_product(self):
  94. self.basket.add_product(self.expensive_item, 1)
  95. self.cond.consume_items(self.basket)
  96. self.assertEquals(0, self.basket.all_lines()[0].quantity_without_discount)
  97. def test_is_consumed_respects_quantity_consumed(self):
  98. self.basket.add_product(self.expensive_item, 1)
  99. self.assertTrue(self.cond.is_satisfied(self.basket))
  100. self.cond.consume_items(self.basket)
  101. self.assertFalse(self.cond.is_satisfied(self.basket))
  102. class CoverageConditionTest(TestCase):
  103. def setUp(self):
  104. self.products = [create_product(Decimal('5.00')), create_product(Decimal('10.00'))]
  105. self.range = models.Range.objects.create(name="Some products")
  106. for product in self.products:
  107. self.range.included_products.add(product)
  108. self.range.included_products.add(product)
  109. self.basket = Basket.objects.create()
  110. self.cond = models.CoverageCondition(range=self.range, type="Coverage", value=2)
  111. def test_empty_basket_fails(self):
  112. self.assertFalse(self.cond.is_satisfied(self.basket))
  113. def test_empty_basket_fails_partial_condition(self):
  114. self.assertFalse(self.cond.is_partially_satisfied(self.basket))
  115. def test_single_item_fails(self):
  116. self.basket.add_product(self.products[0])
  117. self.assertFalse(self.cond.is_satisfied(self.basket))
  118. def test_not_discountable_item_fails(self):
  119. self.products[0].is_discountable = False
  120. self.products[0].save()
  121. self.basket.add_product(self.products[0])
  122. self.basket.add_product(self.products[1])
  123. self.assertFalse(self.cond.is_satisfied(self.basket))
  124. def test_single_item_passes_partial_condition(self):
  125. self.basket.add_product(self.products[0])
  126. self.assertTrue(self.cond.is_partially_satisfied(self.basket))
  127. def test_upsell_message(self):
  128. self.basket.add_product(self.products[0])
  129. self.assertTrue('Buy 1 more' in self.cond.get_upsell_message(self.basket))
  130. def test_duplicate_item_fails(self):
  131. self.basket.add_product(self.products[0])
  132. self.basket.add_product(self.products[0])
  133. self.assertFalse(self.cond.is_satisfied(self.basket))
  134. def test_duplicate_item_passes_partial_condition(self):
  135. self.basket.add_product(self.products[0], 2)
  136. self.assertTrue(self.cond.is_partially_satisfied(self.basket))
  137. def test_covering_items_pass(self):
  138. self.basket.add_product(self.products[0])
  139. self.basket.add_product(self.products[1])
  140. self.assertTrue(self.cond.is_satisfied(self.basket))
  141. def test_covering_items_fail_partial_condition(self):
  142. self.basket.add_product(self.products[0])
  143. self.basket.add_product(self.products[1])
  144. self.assertFalse(self.cond.is_partially_satisfied(self.basket))
  145. def test_covering_items_are_consumed(self):
  146. self.basket.add_product(self.products[0])
  147. self.basket.add_product(self.products[1])
  148. self.cond.consume_items(self.basket)
  149. self.assertEquals(0, self.basket.num_items_without_discount)
  150. def test_consumed_items_checks_affected_items(self):
  151. # Create new offer
  152. range = models.Range.objects.create(name="All products", includes_all_products=True)
  153. cond = models.CoverageCondition(range=range, type="Coverage", value=2)
  154. # Get 4 distinct products in the basket
  155. self.products.extend([create_product(Decimal('15.00')), create_product(Decimal('20.00'))])
  156. for product in self.products:
  157. self.basket.add_product(product)
  158. self.assertTrue(cond.is_satisfied(self.basket))
  159. cond.consume_items(self.basket)
  160. self.assertEquals(2, self.basket.num_items_without_discount)
  161. self.assertTrue(cond.is_satisfied(self.basket))
  162. cond.consume_items(self.basket)
  163. self.assertEquals(0, self.basket.num_items_without_discount)