Bladeren bron

Renamed the shipping methods to be more consistent

master
David Winterbottom 13 jaren geleden
bovenliggende
commit
1db4fd5d77

+ 1
- 1
docs/source/recipes.rst Bestand weergeven

@@ -19,7 +19,7 @@ Catalogue
19 19
 Checkout
20 20
 --------
21 21
 
22
-* :doc:`recipes/custom_shipping_logic`
22
+* :doc:`recipes/how_to_configure_shipping`
23 23
 * :doc:`recipes/enforcing_stock_rules`
24 24
 
25 25
 Lots more to come!

+ 0
- 48
docs/source/recipes/custom_shipping_logic.rst Bestand weergeven

@@ -1,48 +0,0 @@
1
-===========================
2
-How to set shipping charges
3
-===========================
4
-
5
-By default, you can configure shipping by using the built-in ShippingMethod models.  These
6
-support shipping charges that are calculated using an order- and item-level charge.
7
-
8
-Custom shipping calculators
9
----------------------------
10
-
11
-To use a custom shipping calculator, you need to subclass the core shipping Repository class and
12
-override two methods in provide the calculator of your domain.
13
-
14
-First create a ``myshop.shipping`` app and include it in your ``settings.py`` file (removing the ``oscar.shipping``
15
-app in the process.
16
-
17
-Next, create ``methods.py`` and create a new ``Repository`` class that subclasses the core ``Repository`` class but
18
-provides the custom behaviour that you need.
19
-
20
-Here is an example ``methods.py``::
21
-
22
-    from decimal import Decimal
23
-
24
-    from oscar.shipping.methods import Repository as CoreRepository
25
-    from oscar.shipping.abstract_models import ShippingMethod
26
-    
27
-    class FixedChargeMethod(ShippingMethod):
28
-        
29
-        name = 'Fixed charge'
30
-        
31
-        def basket_charge_incl_tax(self):
32
-            return Decimal('12.50')
33
-        
34
-        def basket_charge_excl_tax(self):
35
-            return Decimal('12.50')
36
-    
37
-    class Repository(CoreRepository):
38
-        
39
-        def __init__(self):
40
-            self.method = FixedChargeMethod()
41
-        
42
-        def get_shipping_methods(self, user, basket):
43
-            return [self.method] 
44
-    
45
-        def find_by_code(self, code):
46
-            return self.method
47
-
48
-Here we are using a plain Python object (not a Django model) as the shipping calculator.

+ 68
- 0
docs/source/recipes/how_to_configure_shipping.rst Bestand weergeven

@@ -0,0 +1,68 @@
1
+=========================
2
+How to configure shipping
3
+=========================
4
+
5
+Checkout flow
6
+-------------
7
+
8
+Oscar's checkout is set-up to follow the following steps:
9
+
10
+1. Manage basket
11
+2. Enter/choose shipping address
12
+3. Choose shipping method
13
+4. Choose payment method
14
+5. Preview
15
+6. Enter payment details and submit
16
+
17
+Determining the methods available to a user
18
+-------------------------------------------
19
+
20
+At the shipping method stage, we use a repository object to look up the
21
+shipping methods available to the user.  These methods typically depend on:
22
+
23
+* the user in question (eg. staff get cheaper shipping rates)
24
+* the basket (eg. shipping is charged based on the weight of the basket)
25
+* the shipping address (eg. overseas shipping is more expensive)
26
+
27
+The default repository is ``oscar.apps.shipping.repository.Repository``, which 
28
+has a method ``get_shipping_methods`` for returning all available methods.  By
29
+default, the returned method will be ``oscar.apps.shipping.methods.Free``.
30
+
31
+Set a custom shipping methods
32
+-----------------------------
33
+
34
+To apply your domain logic for shipping, you will need to override
35
+the default repository class (see :doc:`how_to_override_a_class`) and alter
36
+the implementation of the ``get_shipping_methods`` method.  This method
37
+should return a list of "shipping method" classes already instantiated
38
+and holding a reference to the basket instance.
39
+
40
+Building a custom shipping method
41
+---------------------------------
42
+
43
+A shipping method class must define two methods::
44
+
45
+    method.basket_charge_incl_tax()
46
+    method.basket_charge_excl_tax()
47
+
48
+whose responsibilies should be clear.  You can subclass ``oscar.apps.shipping.base.ShippingMethod``
49
+to provide the basic functionality.
50
+
51
+Built-in shipping methods
52
+-------------------------
53
+
54
+Oscar comes with several built-in shipping methods which are easy to use
55
+with a custom repository.
56
+
57
+* ``oscar.apps.shipping.methods.Free``.  No shipping charges.
58
+
59
+* ``oscar.apps.shipping.methods.WeightBased``.  This uses a model ``WeightBand``
60
+  to provide charges for different weight bands.  By default, the method will calculate
61
+  the weight of a product by looking for a 'weight' attribute although this can be
62
+  configured.  
63
+
64
+* ``oscar.apps.shipping.methods.FixedPrice``.  This simply charges a fixed price for 
65
+  shipping, irrespective of the basket contents.
66
+
67
+* ``oscar.apps.shipping.methods.OrderAndItemCharges``.  This is a model which
68
+  specifies a per-order and a per-item level charge.

+ 4
- 4
oscar/apps/shipping/methods.py Bestand weergeven

@@ -1,11 +1,11 @@
1 1
 from decimal import Decimal as D
2 2
 
3 3
 from oscar.apps.shipping.base import ShippingMethod
4
-from oscar.apps.shipping.models import OrderAndItemLevelChargeMethod, WeightBand
4
+from oscar.apps.shipping.models import OrderAndItemCharges, WeightBand
5 5
 from oscar.apps.shipping import Scales
6 6
 
7 7
 
8
-class FreeShipping(ShippingMethod):
8
+class Free(ShippingMethod):
9 9
     """
10 10
     Simple method for free shipping
11 11
     """
@@ -19,7 +19,7 @@ class FreeShipping(ShippingMethod):
19 19
         return D('0.00')
20 20
     
21 21
 
22
-class FixedPriceShipping(ShippingMethod):
22
+class FixedPrice(ShippingMethod):
23 23
     code = 'fixed-price-shipping'
24 24
     name = 'Fixed price shipping'
25 25
     
@@ -36,7 +36,7 @@ class FixedPriceShipping(ShippingMethod):
36 36
         return self.charge_excl_tax
37 37
 
38 38
 
39
-class WeightBasedChargesMethod(ShippingMethod):
39
+class WeightBased(ShippingMethod):
40 40
 
41 41
     def __init__(self, code, weight_attribute='weight', upper_charge=None):
42 42
         self.code = code

+ 1
- 1
oscar/apps/shipping/models.py Bestand weergeven

@@ -6,7 +6,7 @@ from django.template.defaultfilters import slugify
6 6
 from django.conf import settings
7 7
 
8 8
 
9
-class OrderAndItemLevelChargeMethod(models.Model):
9
+class OrderAndItemCharges(models.Model):
10 10
     """
11 11
     Standard shipping method
12 12
     

+ 4
- 4
oscar/apps/shipping/repository.py Bestand weergeven

@@ -1,4 +1,4 @@
1
-from oscar.apps.shipping.methods import FreeShipping, OrderAndItemLevelChargeMethod
1
+from oscar.apps.shipping.methods import Free
2 2
 
3 3
 
4 4
 class Repository(object):
@@ -16,7 +16,7 @@ class Repository(object):
16 16
         this behaviour can easily be overridden by subclassing this class
17 17
         and overriding this method.
18 18
         """ 
19
-        methods = [FreeShipping()]
19
+        methods = [Free()]
20 20
         for method in methods:
21 21
             method.set_basket(basket)
22 22
         return methods
@@ -25,6 +25,6 @@ class Repository(object):
25 25
         """
26 26
         Return the appropriate Method object for the given code
27 27
         """
28
-        if code == FreeShipping.code:
29
-            return FreeShipping()
28
+        if code == Free.code:
29
+            return Free()
30 30
         return None

+ 19
- 19
oscar/apps/shipping/tests.py Bestand weergeven

@@ -4,8 +4,8 @@ from django.utils import unittest
4 4
 from django.test.client import Client
5 5
 from django.contrib.auth.models import User
6 6
 
7
-from oscar.apps.shipping.methods import FreeShipping, FixedPriceShipping, WeightBasedChargesMethod
8
-from oscar.apps.shipping.models import OrderAndItemLevelChargeMethod, WeightBand
7
+from oscar.apps.shipping.methods import Free, FixedPrice, WeightBased
8
+from oscar.apps.shipping.models import OrderAndItemCharges, WeightBand
9 9
 from oscar.apps.shipping.repository import Repository
10 10
 from oscar.apps.shipping import Scales
11 11
 from oscar.apps.basket.models import Basket
@@ -13,10 +13,10 @@ from oscar.test.helpers import create_product
13 13
 from oscar.test.decorators import dataProvider
14 14
 
15 15
 
16
-class FreeShippingTest(unittest.TestCase):
16
+class FreeTest(unittest.TestCase):
17 17
 
18 18
     def setUp(self):
19
-        self.method = FreeShipping()
19
+        self.method = Free()
20 20
     
21 21
     def test_shipping_is_free_for_empty_basket(self):
22 22
         basket = Basket()
@@ -32,17 +32,17 @@ class FreeShippingTest(unittest.TestCase):
32 32
         self.assertEquals(D('0.00'), self.method.basket_charge_excl_tax())
33 33
         
34 34
         
35
-class FixedPriceShippingTest(unittest.TestCase):        
35
+class FixedPriceTest(unittest.TestCase):        
36 36
     
37 37
     def test_fixed_price_shipping_charges_for_empty_basket(self):
38
-        method = FixedPriceShipping(D('10.00'), D('10.00'))
38
+        method = FixedPrice(D('10.00'), D('10.00'))
39 39
         basket = Basket()
40 40
         method.set_basket(basket)
41 41
         self.assertEquals(D('10.00'), method.basket_charge_incl_tax())
42 42
         self.assertEquals(D('10.00'), method.basket_charge_excl_tax())
43 43
         
44 44
     def test_fixed_price_shipping_assumes_no_tax(self):
45
-        method = FixedPriceShipping(D('10.00'))
45
+        method = FixedPrice(D('10.00'))
46 46
         basket = Basket()
47 47
         method.set_basket(basket)
48 48
         self.assertEquals(D('10.00'), method.basket_charge_excl_tax())
@@ -54,16 +54,16 @@ class FixedPriceShippingTest(unittest.TestCase):
54 54
         
55 55
     @dataProvider(shipping_values)    
56 56
     def test_different_values(self, value):
57
-        method = FixedPriceShipping(D(value))
57
+        method = FixedPrice(D(value))
58 58
         basket = Basket()
59 59
         method.set_basket(basket)
60 60
         self.assertEquals(D(value), method.basket_charge_excl_tax())
61 61
         
62 62
         
63
-class OrderAndItemLevelChargeMethodTests(unittest.TestCase):
63
+class OrderAndItemChargesTests(unittest.TestCase):
64 64
     
65 65
     def setUp(self):
66
-        self.method = OrderAndItemLevelChargeMethod(price_per_order=D('5.00'), price_per_item=D('1.00'))
66
+        self.method = OrderAndItemCharges(price_per_order=D('5.00'), price_per_item=D('1.00'))
67 67
         self.basket = Basket.objects.create()
68 68
         self.method.set_basket(self.basket)
69 69
     
@@ -81,10 +81,10 @@ class OrderAndItemLevelChargeMethodTests(unittest.TestCase):
81 81
         self.assertEquals(D('5.00') + 7*D('1.00'), self.method.basket_charge_incl_tax())
82 82
 
83 83
 
84
-class ZeroFreeShippingThresholdTest(unittest.TestCase):
84
+class ZeroFreeThresholdTest(unittest.TestCase):
85 85
     
86 86
     def setUp(self):
87
-        self.method = OrderAndItemLevelChargeMethod(price_per_order=D('10.00'), free_shipping_threshold=D('0.00'))
87
+        self.method = OrderAndItemCharges(price_per_order=D('10.00'), free_shipping_threshold=D('0.00'))
88 88
         self.basket = Basket.objects.create()
89 89
         self.method.set_basket(self.basket)
90 90
     
@@ -97,10 +97,10 @@ class ZeroFreeShippingThresholdTest(unittest.TestCase):
97 97
         self.assertEquals(D('0.00'), self.method.basket_charge_incl_tax())
98 98
 
99 99
 
100
-class NonZeroFreeShippingThresholdTest(unittest.TestCase):
100
+class NonZeroFreeThresholdTest(unittest.TestCase):
101 101
     
102 102
     def setUp(self):
103
-        self.method = OrderAndItemLevelChargeMethod(price_per_order=D('10.00'), free_shipping_threshold=D('20.00'))
103
+        self.method = OrderAndItemCharges(price_per_order=D('10.00'), free_shipping_threshold=D('20.00'))
104 104
         self.basket = Basket.objects.create()
105 105
         self.method.set_basket(self.basket)
106 106
         
@@ -123,7 +123,7 @@ class NonZeroFreeShippingThresholdTest(unittest.TestCase):
123 123
 class WeightBasedShippingTests(unittest.TestCase):
124 124
 
125 125
     def test_no_bands_leads_to_zero_charges(self):
126
-        method = WeightBasedChargesMethod('dummy')
126
+        method = WeightBased('dummy')
127 127
         basket = Basket.objects.create()
128 128
         method.set_basket(basket)
129 129
 
@@ -133,7 +133,7 @@ class WeightBasedShippingTests(unittest.TestCase):
133 133
     def test_lower_band_basket(self):
134 134
         WeightBand.objects.create(method_code='standard', upper_limit=1, charge=D('4.00'))
135 135
         WeightBand.objects.create(method_code='standard', upper_limit=3, charge=D('12.00'))
136
-        method = WeightBasedChargesMethod('standard')
136
+        method = WeightBased('standard')
137 137
 
138 138
         basket = Basket.objects.create()
139 139
         basket.add_product(create_product(attributes={'weight': 0.5}))
@@ -144,7 +144,7 @@ class WeightBasedShippingTests(unittest.TestCase):
144 144
     def test_inner_band_basket(self):
145 145
         WeightBand.objects.create(method_code='standard', upper_limit=1, charge=D('4.00'))
146 146
         WeightBand.objects.create(method_code='standard', upper_limit=3, charge=D('12.00'))
147
-        method = WeightBasedChargesMethod('standard')
147
+        method = WeightBased('standard')
148 148
 
149 149
         basket = Basket.objects.create()
150 150
         basket.add_product(create_product(attributes={'weight': 0.5}))
@@ -156,7 +156,7 @@ class WeightBasedShippingTests(unittest.TestCase):
156 156
     def test_outer_band_basket(self):
157 157
         WeightBand.objects.create(method_code='standard', upper_limit=1, charge=D('4.00'))
158 158
         WeightBand.objects.create(method_code='standard', upper_limit=3, charge=D('12.00'))
159
-        method = WeightBasedChargesMethod('standard', upper_charge=D('30.00'))
159
+        method = WeightBased('standard', upper_charge=D('30.00'))
160 160
 
161 161
         basket = Basket.objects.create()
162 162
         basket.add_product(create_product(attributes={'weight': 10.5}))
@@ -260,5 +260,5 @@ class RepositoryTests(unittest.TestCase):
260 260
         user, basket = User(), Basket()
261 261
         methods = self.repo.get_shipping_methods(user, basket)
262 262
         self.assertEqual(1, len(methods))
263
-        self.assertTrue(isinstance(methods[0], FreeShipping))
263
+        self.assertTrue(isinstance(methods[0], Free))
264 264
 

Laden…
Annuleren
Opslaan