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.

model_method_tests.py 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. from decimal import Decimal as D
  2. from django.test import TestCase
  3. from oscar.apps.offer.applicator import Applicator
  4. from oscar.apps.offer.models import Benefit
  5. from oscar.apps.shipping.models import OrderAndItemCharges, WeightBased
  6. from oscar.apps.shipping.repository import Repository
  7. from oscar.core.compat import get_user_model
  8. from oscar.test import factories
  9. User = get_user_model()
  10. class TestOrderAndItemCharges(TestCase):
  11. def setUp(self):
  12. self.method = OrderAndItemCharges(
  13. price_per_order=D('5.00'), price_per_item=D('1.00'))
  14. def test_tax_is_known(self):
  15. basket = factories.create_basket(empty=True)
  16. charge = self.method.calculate(basket)
  17. self.assertTrue(charge.is_tax_known)
  18. def test_returns_order_level_charge_for_empty_basket(self):
  19. basket = factories.create_basket(empty=True)
  20. charge = self.method.calculate(basket)
  21. self.assertEqual(D('5.00'), charge.incl_tax)
  22. def test_single_item_basket(self):
  23. basket = factories.create_basket(empty=False)
  24. charge = self.method.calculate(basket)
  25. self.assertEqual(D('5.00') + D('1.00'),
  26. charge.incl_tax)
  27. def test_single_item_basket_that_doesnt_require_shipping(self):
  28. # Create a product that doesn't require shipping
  29. record = factories.create_stockrecord()
  30. product = record.product
  31. product.product_class.requires_shipping = False
  32. product.product_class.save()
  33. basket = factories.create_basket(empty=True)
  34. basket.add_product(record.product)
  35. charge = self.method.calculate(basket)
  36. self.assertEqual(D('5.00'), charge.incl_tax)
  37. def test_multi_item_basket(self):
  38. basket = factories.create_basket(empty=True)
  39. record = factories.create_stockrecord()
  40. basket.add_product(record.product, 7)
  41. charge = self.method.calculate(basket)
  42. self.assertEqual(D('5.00') + 7*D('1.00'), charge.incl_tax)
  43. class ZeroFreeThresholdTest(TestCase):
  44. def setUp(self):
  45. self.method = OrderAndItemCharges(
  46. price_per_order=D('10.00'), free_shipping_threshold=D('0.00'))
  47. self.basket = factories.create_basket(empty=True)
  48. def test_free_shipping_with_empty_basket(self):
  49. charge = self.method.calculate(self.basket)
  50. self.assertEqual(D('0.00'), charge.incl_tax)
  51. def test_free_shipping_with_nonempty_basket(self):
  52. record = factories.create_stockrecord(price_excl_tax=D('5.00'))
  53. self.basket.add_product(record.product)
  54. charge = self.method.calculate(self.basket)
  55. self.assertEqual(D('0.00'), charge.incl_tax)
  56. class TestNonZeroFreeThreshold(TestCase):
  57. def setUp(self):
  58. self.method = OrderAndItemCharges(
  59. price_per_order=D('10.00'), free_shipping_threshold=D('20.00'))
  60. self.basket = factories.create_basket(empty=True)
  61. def test_basket_below_threshold(self):
  62. record = factories.create_stockrecord(price_excl_tax=D('5.00'))
  63. self.basket.add_product(record.product)
  64. charge = self.method.calculate(self.basket)
  65. self.assertEqual(D('10.00'), charge.incl_tax)
  66. def test_basket_on_threshold(self):
  67. record = factories.create_stockrecord(price_excl_tax=D('5.00'))
  68. self.basket.add_product(record.product, quantity=4)
  69. charge = self.method.calculate(self.basket)
  70. self.assertEqual(D('0.00'), charge.incl_tax)
  71. def test_basket_above_threshold(self):
  72. record = factories.create_stockrecord(price_excl_tax=D('5.00'))
  73. self.basket.add_product(record.product, quantity=8)
  74. charge = self.method.calculate(self.basket)
  75. self.assertEqual(D('0.00'), charge.incl_tax)
  76. class WeightBasedMethodTests(TestCase):
  77. def setUp(self):
  78. self.standard = WeightBased.objects.create(name='Standard')
  79. self.express = WeightBased.objects.create(name='Express')
  80. def test_zero_weight_baskets_can_have_a_charge(self):
  81. self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  82. charge = self.standard.get_charge(0)
  83. self.assertEqual(D('4.00'), charge)
  84. def test_zero_weight_baskets_can_have_no_charge(self):
  85. self.standard.bands.create(upper_limit=0, charge=D('0.00'))
  86. self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  87. charge = self.standard.get_charge(0)
  88. self.assertEqual(D('0.00'), charge)
  89. def test_get_band_for_zero_weight(self):
  90. self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  91. charge = self.standard.get_charge(0)
  92. self.assertEqual(D('4.00'), charge)
  93. def test_get_band_for_lower_weight(self):
  94. band = self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  95. fetched_band = self.standard.get_band_for_weight(0.5)
  96. self.assertEqual(band.id, fetched_band.id)
  97. def test_get_band_for_higher_weight(self):
  98. self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  99. fetched_band = self.standard.get_band_for_weight(1.5)
  100. self.assertIsNone(fetched_band)
  101. def test_get_band_for_matching_weight(self):
  102. band = self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  103. fetched_band = self.standard.get_band_for_weight(1)
  104. self.assertEqual(band.id, fetched_band.id)
  105. def test_weight_to_is_upper_bound(self):
  106. band = self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  107. self.assertEqual(1, band.weight_to)
  108. def test_weight_from_for_single_band(self):
  109. band = self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  110. self.assertEqual(0, band.weight_from)
  111. def test_weight_from_for_multiple_bands(self):
  112. self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  113. band = self.express.bands.create(upper_limit=2, charge=D('8.00'))
  114. self.assertEqual(0, band.weight_from)
  115. def test_get_band_for_series_of_bands(self):
  116. self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  117. self.standard.bands.create(upper_limit=2, charge=D('8.00'))
  118. self.standard.bands.create(upper_limit=3, charge=D('12.00'))
  119. self.assertEqual(D('4.00'), self.standard.get_band_for_weight(0.5).charge)
  120. self.assertEqual(D('8.00'), self.standard.get_band_for_weight(1.5).charge)
  121. self.assertEqual(D('12.00'), self.standard.get_band_for_weight(2.5).charge)
  122. def test_get_band_for_series_of_bands_from_different_methods(self):
  123. self.express.bands.create(upper_limit=2, charge=D('8.00'))
  124. self.standard.bands.create(upper_limit=1, charge=D('4.00'))
  125. self.standard.bands.create(upper_limit=3, charge=D('12.00'))
  126. self.assertEqual(D('12.00'), self.standard.get_band_for_weight(2.5).charge)
  127. def test_for_smoke_with_basket_charge(self):
  128. basket = factories.create_basket(empty=True)
  129. charge = self.standard.calculate(basket)
  130. self.assertEqual(D('0.00'), charge.incl_tax)
  131. self.assertTrue(charge.is_tax_known)
  132. def test_simple_shipping_cost_scenario_handled_correctly(self):
  133. basket = factories.BasketFactory()
  134. product_attribute_value = factories.ProductAttributeValueFactory(
  135. value_float=2.5)
  136. basket.add_product(product_attribute_value.product)
  137. expected_charge = D('3.00')
  138. self.standard.bands.create(upper_limit=3, charge=expected_charge)
  139. charge = self.standard.calculate(basket)
  140. self.assertEqual(expected_charge, charge.excl_tax)
  141. def test_overflow_shipping_cost_scenario_handled_correctly(self):
  142. basket = factories.BasketFactory()
  143. product_attribute_value = factories.ProductAttributeValueFactory(
  144. value_float=2.5)
  145. basket.add_product(product_attribute_value.product)
  146. self.standard.bands.create(upper_limit=1, charge=D('1.00'))
  147. self.standard.bands.create(upper_limit=2, charge=D('2.00'))
  148. charge = self.standard.calculate(basket)
  149. self.assertEqual(D('1.00') + D('2.00'), charge.excl_tax)
  150. def test_zero_charge_discount(self):
  151. # Since Repository.apply_shipping_offer() returns the original
  152. # shipping method object on a free shipping charge, it's discount()
  153. # method should be callable and also indicate it won't add discounts.
  154. basket = factories.create_basket()
  155. self.assertEqual(D('0.00'), self.standard.discount(basket))
  156. def test_zero_charge_with_shipping_discount(self):
  157. offer = factories.create_offer(
  158. benefit=Benefit.objects.create(
  159. type=Benefit.SHIPPING_FIXED_PRICE, value=1),
  160. )
  161. basket = factories.create_basket()
  162. Applicator().apply_offers(basket, [offer])
  163. # Similar to test_zero_charge_discount(),
  164. # but now test how the repository deals with it.
  165. method = Repository().apply_shipping_offer(
  166. basket, self.standard, offer)
  167. self.assertEqual(D('0.00'), method.discount(basket))