Kaynağa Gözat

Rewrote submit order as a class.

Split all the steps into separate methods.
Also finished removing all references to "delivery"
master
David Winterbottom 15 yıl önce
ebeveyn
işleme
f10d8fbe6a

+ 2
- 1
README.md Dosyayı Görüntüle

140
 
140
 
141
 Look in the TODO file for things to hack on...
141
 Look in the TODO file for things to hack on...
142
     
142
     
143
-
143
+### Conventions
144
+* URLs use hyphens not underscores
144
 
145
 

+ 1
- 0
examples/defaultshop/settings.py Dosyayı Görüntüle

73
     'django.middleware.csrf.CsrfViewMiddleware',
73
     'django.middleware.csrf.CsrfViewMiddleware',
74
     'django.contrib.auth.middleware.AuthenticationMiddleware',
74
     'django.contrib.auth.middleware.AuthenticationMiddleware',
75
     'django.contrib.messages.middleware.MessageMiddleware',
75
     'django.contrib.messages.middleware.MessageMiddleware',
76
+    'django.middleware.transaction.TransactionMiddleware',
76
 )
77
 )
77
 
78
 
78
 ROOT_URLCONF = 'urls'
79
 ROOT_URLCONF = 'urls'

+ 19
- 13
oscar/address/abstract_models.py Dosyayı Görüntüle

12
     Core address object
12
     Core address object
13
     
13
     
14
     This is normally subclassed and extended to provide models for 
14
     This is normally subclassed and extended to provide models for 
15
-    delivery and billing addresses.
15
+    shipping and billing addresses.
16
     """
16
     """
17
     # @todo: Need a way of making these choice lists configurable 
17
     # @todo: Need a way of making these choice lists configurable 
18
     # per project
18
     # per project
71
         return " ".join([part for part in [self.title, self.first_name, self.last_name] if part])
71
         return " ".join([part for part in [self.title, self.first_name, self.last_name] if part])
72
         
72
         
73
     def __unicode__(self):
73
     def __unicode__(self):
74
-        parts = (self.get_salutation(), self.line1, self.line2, self.line3, self.line4,
74
+        parts = (self.salutation(), self.line1, self.line2, self.line3, self.line4,
75
                  self.postcode, self.country)
75
                  self.postcode, self.country)
76
         return u", ".join([part for part in parts if part])
76
         return u", ".join([part for part in parts if part])
77
 
77
 
78
 
78
 
79
-class AbstractDeliveryAddress(AbstractAddress):
80
-    """
81
-    Delivery address 
79
+class AbstractShippingAddress(AbstractAddress):
80
+    u"""
81
+    Shipping address 
82
     """
82
     """
83
     phone_number = models.CharField(max_length=32, blank=True, null=True)
83
     phone_number = models.CharField(max_length=32, blank=True, null=True)
84
     notes = models.TextField(blank=True, null=True) 
84
     notes = models.TextField(blank=True, null=True) 
85
     
85
     
86
     class Meta:
86
     class Meta:
87
         abstract = True
87
         abstract = True
88
-        verbose_name_plural = "Delivery addresses"
88
+        verbose_name_plural = "shipping addresses"
89
         
89
         
90
         
90
         
91
-class AbstractUserAddress(AbstractDeliveryAddress):
92
-    """
91
+class AbstractUserAddress(AbstractShippingAddress):
92
+    u"""
93
     A user address which forms an "AddressBook".
93
     A user address which forms an "AddressBook".
94
     
94
     
95
-    We use a separate model to delivery and billing (even though there will be
96
-    some data duplication) because we don't want delivery/billing addresses changed
95
+    We use a separate model to shipping and billing (even though there will be
96
+    some data duplication) because we don't want shipping/billing addresses changed
97
     or deleted once an order has been placed.  By having a separate model, we allow
97
     or deleted once an order has been placed.  By having a separate model, we allow
98
     users  
98
     users  
99
     """
99
     """
100
     user = models.ForeignKey('auth.User', related_name='addresses')
100
     user = models.ForeignKey('auth.User', related_name='addresses')
101
-    is_primary = models.BooleanField(max_length=32, default=False)
101
+    
102
+    # We keep track of the number of times an address has been used
103
+    # as a shipping address so we can show the most popular ones 
104
+    # first at the checkout.
105
+    num_orders = models.PositiveIntegerField(default=0)
102
     hash = models.CharField(max_length=255, db_index=True)
106
     hash = models.CharField(max_length=255, db_index=True)
103
     date_created = models.DateTimeField(auto_now_add=True)
107
     date_created = models.DateTimeField(auto_now_add=True)
104
     
108
     
105
     def generate_hash(self):
109
     def generate_hash(self):
106
-        return zlib.crc32(self.summary())
107
-    
110
+        # We use an uppercase version of the summary
111
+        return zlib.crc32(self.summary().strip().upper())
112
+
108
     def save(self, *args, **kwargs):
113
     def save(self, *args, **kwargs):
109
         # Save a hash of the address fields so we can check whether two 
114
         # Save a hash of the address fields so we can check whether two 
110
         # addresses are the same to avoid saving duplicates
115
         # addresses are the same to avoid saving duplicates
114
     class Meta:
119
     class Meta:
115
         abstract = True
120
         abstract = True
116
         verbose_name_plural = "User addresses"
121
         verbose_name_plural = "User addresses"
122
+        ordering = ['-num_orders']
117
 
123
 
118
 
124
 
119
 class AbstractBillingAddress(AbstractAddress):
125
 class AbstractBillingAddress(AbstractAddress):

+ 6
- 6
oscar/basket/models.py Dosyayı Görüntüle

23
     pass
23
     pass
24
 
24
 
25
 # Example signal handler to enforce stock rules
25
 # Example signal handler to enforce stock rules
26
-#@receiver(pre_save, sender=Line)
27
-#def handle_line_save(sender, **kwargs):
28
-#    if 'instance' in kwargs:
29
-#        quantity = int(kwargs['instance'].quantity)
30
-#        if quantity > 4:
31
-#            raise InvalidBasketLineError("You are only allowed to purchase a maximum of 4 of these")
26
+@receiver(pre_save, sender=Line)
27
+def handle_line_save(sender, **kwargs):
28
+    if 'instance' in kwargs:
29
+        quantity = int(kwargs['instance'].quantity)
30
+        if quantity > 4:
31
+            raise InvalidBasketLineError("You are only allowed to purchase a maximum of 4 of these")

+ 5
- 5
oscar/basket/views.py Dosyayı Görüntüle

84
         try:
84
         try:
85
             super(BasketView, self).handle_POST()
85
             super(BasketView, self).handle_POST()
86
         except basket_models.Basket.DoesNotExist:
86
         except basket_models.Basket.DoesNotExist:
87
-            messages.error(request, "Unable to find your basket")
87
+            messages.error(self.request, "Unable to find your basket")
88
         except basket_models.InvalidBasketLineError, e:
88
         except basket_models.InvalidBasketLineError, e:
89
-            messages.error(request, str(e))
89
+            messages.error(self.request, str(e))
90
             
90
             
91
     def do_flush(self, basket):
91
     def do_flush(self, basket):
92
         basket.flush()
92
         basket.flush()
123
         try:
123
         try:
124
             super(LineView, self).handle_POST()
124
             super(LineView, self).handle_POST()
125
         except basket_models.Basket.DoesNotExist:
125
         except basket_models.Basket.DoesNotExist:
126
-                messages.error(request, "You don't have a basket to adjust the lines of")
126
+                messages.error(self.request, "You don't have a basket to adjust the lines of")
127
         except basket_models.Line.DoesNotExist:
127
         except basket_models.Line.DoesNotExist:
128
-            messages.error(request, "Unable to find a line with reference %s in your basket" % self.kwargs['line_reference'])
128
+            messages.error(self.request, "Unable to find a line with reference %s in your basket" % self.kwargs['line_reference'])
129
         except basket_models.InvalidBasketLineError, e:
129
         except basket_models.InvalidBasketLineError, e:
130
-            messages.error(request, str(e))
130
+            messages.error(self.request, str(e))
131
             
131
             
132
     def _get_quantity(self):
132
     def _get_quantity(self):
133
         if 'quantity' in self.request.POST:
133
         if 'quantity' in self.request.POST:

+ 1
- 1
oscar/checkout/calculators.py Dosyayı Görüntüle

10
     def __init__(self, request):
10
     def __init__(self, request):
11
         # We store a reference to the request as the total may 
11
         # We store a reference to the request as the total may 
12
         # depend on the user or the other checkout data in the session.
12
         # depend on the user or the other checkout data in the session.
13
-        # Further, it is very likely that it will as delivery method
13
+        # Further, it is very likely that it will as shipping method
14
         # always changes the order total.
14
         # always changes the order total.
15
         self.request = request
15
         self.request = request
16
     
16
     

+ 3
- 3
oscar/checkout/forms.py Dosyayı Görüntüle

2
 
2
 
3
 from oscar.services import import_module
3
 from oscar.services import import_module
4
 
4
 
5
-order_models = import_module('order.models', ['DeliveryAddress'])
5
+order_models = import_module('order.models', ['ShippingAddress'])
6
 
6
 
7
 
7
 
8
-class DeliveryAddressForm(ModelForm):
8
+class ShippingAddressForm(ModelForm):
9
     
9
     
10
     class Meta:
10
     class Meta:
11
-        model = order_models.DeliveryAddress
11
+        model = order_models.ShippingAddress
12
         exclude = ('user',)
12
         exclude = ('user',)
13
 
13
 

+ 1
- 1
oscar/checkout/templates/checkout/gateway.html Dosyayı Görüntüle

16
            order is viewable in your order history.</p>
16
            order is viewable in your order history.</p>
17
     </dl>
17
     </dl>
18
     <dt>
18
     <dt>
19
-        <a href="{% url oscar-checkout-delivery-address %}">Checkout anonymously</a>
19
+        <a href="{% url oscar-checkout-shipping-address %}">Checkout anonymously</a>
20
     </dt>
20
     </dt>
21
     <dl>
21
     <dl>
22
         <p>You can checkout without signing in or registering.  You will be given the opportunity to 
22
         <p>You can checkout without signing in or registering.  You will be given the opportunity to 

+ 12
- 12
oscar/checkout/templates/checkout/preview.html Dosyayı Görüntüle

7
 
7
 
8
 {% block content %}
8
 {% block content %}
9
 
9
 
10
-<h3>Delivery address</h3>
10
+<h3>Shipping address</h3>
11
 <hr />
11
 <hr />
12
 <table>
12
 <table>
13
     <tr>
13
     <tr>
14
         <th>Address</th>
14
         <th>Address</th>
15
         <td>
15
         <td>
16
-            {% for field in delivery_addr.active_address_fields %}
16
+            {% for field in shipping_addr.active_address_fields %}
17
             {{ field }}<br/>
17
             {{ field }}<br/>
18
             {% endfor %}
18
             {% endfor %}
19
         </td>
19
         </td>
20
     </tr>
20
     </tr>
21
-    {% if delivery_addr.phone_number %}
21
+    {% if shipping_addr.phone_number %}
22
     <tr>
22
     <tr>
23
         <th>Concact number</th>
23
         <th>Concact number</th>
24
-        <td>delivery_addr.phone_number</td>
24
+        <td>shipping_addr.phone_number</td>
25
     </tr>
25
     </tr>
26
     {% endif %}
26
     {% endif %}
27
-    {% if delivery_addr.notes %}
27
+    {% if shipping_addr.notes %}
28
     <tr>
28
     <tr>
29
-        <th>Delivery notes</th>
30
-        <td>delivery_addr.notes</td>
29
+        <th>Shipping notes</th>
30
+        <td>shipping_addr.notes</td>
31
     </tr>
31
     </tr>
32
     {% endif %} 
32
     {% endif %} 
33
 </table>
33
 </table>
34
-<a href="{% url oscar-checkout-delivery-address %}">Change delivery address</a>
34
+<a href="{% url oscar-checkout-shipping-address %}">Change shipping address</a>
35
 
35
 
36
-<h3>Delivery method</h3>
36
+<h3>Shipping method</h3>
37
 <hr />
37
 <hr />
38
 
38
 
39
 <h3>Payment</h3>
39
 <h3>Payment</h3>
69
         <td>{{ basket.total_incl_tax|floatformat:2 }}</td>
69
         <td>{{ basket.total_incl_tax|floatformat:2 }}</td>
70
     </tr>
70
     </tr>
71
     <tr>
71
     <tr>
72
-        <td colspan="5">Delivery charge</td>
73
-        <td>{{ delivery_total_excl_tax|floatformat:2 }}</td>
74
-        <td>{{ delivery_total_incl_tax|floatformat:2 }}</td>
72
+        <td colspan="5">Shipping charge</td>
73
+        <td>{{ shipping_total_excl_tax|floatformat:2 }}</td>
74
+        <td>{{ shipping_total_incl_tax|floatformat:2 }}</td>
75
     </tr>
75
     </tr>
76
     <tr>
76
     <tr>
77
         <td colspan="6">Order total</td>
77
         <td colspan="6">Order total</td>

oscar/checkout/templates/checkout/delivery_address.html → oscar/checkout/templates/checkout/shipping_address.html Dosyayı Görüntüle

6
 
6
 
7
 
7
 
8
 {% block content %}
8
 {% block content %}
9
-<h3>Delivery address</h3>
9
+<h3>Shipping address</h3>
10
 <hr />
10
 <hr />
11
 
11
 
12
 {% if addresses %}
12
 {% if addresses %}
13
-<h4>Choose a delivery address</h4>
13
+<h4>Choose a shipping address</h4>
14
 <ul>
14
 <ul>
15
     {% for address in addresses %}
15
     {% for address in addresses %}
16
     <li>
16
     <li>
17
     {{ address.summary }}
17
     {{ address.summary }}
18
-        <form action="{% url oscar-checkout-delivery-address %}" method="post">
18
+        <form action="{% url oscar-checkout-shipping-address %}" method="post">
19
             {% csrf_token %}
19
             {% csrf_token %}
20
-            <input type="hidden" name="action" value="deliver_to" />
20
+            <input type="hidden" name="action" value="ship_to" />
21
             <input type="hidden" name="address_id" value="{{ address.id }}" />
21
             <input type="hidden" name="address_id" value="{{ address.id }}" />
22
-            <input type="submit" value="Delivery to this address" />
22
+            <input type="submit" value="Ship to this address" />
23
         </form>
23
         </form>
24
-        <form action="{% url oscar-checkout-delivery-address %}" method="post">
24
+        <form action="{% url oscar-checkout-shipping-address %}" method="post">
25
             {% csrf_token %}
25
             {% csrf_token %}
26
             <input type="hidden" name="action" value="delete" />
26
             <input type="hidden" name="action" value="delete" />
27
             <input type="hidden" name="address_id" value="{{ address.id }}" />
27
             <input type="hidden" name="address_id" value="{{ address.id }}" />
33
 </form>
33
 </form>
34
 {% endif %}
34
 {% endif %}
35
     
35
     
36
-<h4>Enter a delivery address</h4>
37
-<form action="{% url oscar-checkout-delivery-address %}" method="post">
36
+<h4>Enter a shipping address</h4>
37
+<form action="{% url oscar-checkout-shipping-address %}" method="post">
38
     {% csrf_token %}
38
     {% csrf_token %}
39
     {{ form.as_p }}
39
     {{ form.as_p }}
40
-    <p><label><input type="checkbox" id="save_as_default" name="save_as_default"/>Save as default delivery address</label></p>
41
-    <p><input type="submit" value="Save delivery address" /></p>
40
+    <p><input type="submit" value="Save shipping address" /></p>
42
 </form>
41
 </form>
43
 
42
 
44
-<h3>Delivery method</h3>
43
+<h3>Shipping method</h3>
45
 <hr />
44
 <hr />
46
 
45
 
47
 <h3>Payment</h3>
46
 <h3>Payment</h3>
77
         <td>{{ basket.total_incl_tax|floatformat:2 }}</td>
76
         <td>{{ basket.total_incl_tax|floatformat:2 }}</td>
78
     </tr>
77
     </tr>
79
     <tr>
78
     <tr>
80
-        <td colspan="5">Delivery charge</td>
81
-        <td>{{ delivery_total_excl_tax|floatformat:2 }}</td>
82
-        <td>{{ delivery_total_incl_tax|floatformat:2 }}</td>
79
+        <td colspan="5">shipping charge</td>
80
+        <td>{{ shipping_total_excl_tax|floatformat:2 }}</td>
81
+        <td>{{ shipping_total_incl_tax|floatformat:2 }}</td>
83
     </tr>
82
     </tr>
84
     <tr>
83
     <tr>
85
         <td colspan="6">Order total</td>
84
         <td colspan="6">Order total</td>

+ 9
- 4
oscar/checkout/urls.py Dosyayı Görüntüle

1
 from django.conf.urls.defaults import *
1
 from django.conf.urls.defaults import *
2
 
2
 
3
+from oscar.checkout.views import SubmitView
4
+
5
+def submit_view(request, *args, **kwargs):
6
+    return SubmitView()(request, *args, **kwargs)
7
+
3
 urlpatterns = patterns('oscar.checkout.views',
8
 urlpatterns = patterns('oscar.checkout.views',
4
     url(r'^$', 'index', name='oscar-checkout-index'),
9
     url(r'^$', 'index', name='oscar-checkout-index'),
5
-    url(r'delivery_address/$', 'delivery_address', name='oscar-checkout-delivery-address'),
6
-    url(r'delivery_method/$', 'delivery_method', name='oscar-checkout-delivery-method'),
10
+    url(r'shipping-address/$', 'shipping_address', name='oscar-checkout-shipping-address'),
11
+    url(r'shipping-method/$', 'shipping_method', name='oscar-checkout-shipping-method'),
7
     url(r'payment/$', 'payment', name='oscar-checkout-payment'),
12
     url(r'payment/$', 'payment', name='oscar-checkout-payment'),
8
     url(r'preview/$', 'preview', name='oscar-checkout-preview'),
13
     url(r'preview/$', 'preview', name='oscar-checkout-preview'),
9
-    url(r'submit/$', 'submit', name='oscar-checkout-submit'),
10
-    url(r'thank_you/$', 'thank_you', name='oscar-checkout-thank-you'),
14
+    url(r'submit/$', submit_view, name='oscar-checkout-submit'),
15
+    url(r'thank-you/$', 'thank_you', name='oscar-checkout-thank-you'),
11
 )
16
 )
12
 
17
 

+ 2
- 2
oscar/checkout/utils.py Dosyayı Görüntüle

8
     """
8
     """
9
     
9
     
10
     # List of URL names that have to be completed (in this order)
10
     # List of URL names that have to be completed (in this order)
11
-    urls_for_steps = ['oscar-checkout-delivery-address',
12
-                      'oscar-checkout-delivery-method',
11
+    urls_for_steps = ['oscar-checkout-shipping-address',
12
+                      'oscar-checkout-shipping-method',
13
                       'oscar-checkout-payment',
13
                       'oscar-checkout-payment',
14
                       'oscar-checkout-preview',
14
                       'oscar-checkout-preview',
15
                       'oscar-checkout-submit',]
15
                       'oscar-checkout-submit',]

+ 139
- 85
oscar/checkout/views.py Dosyayı Görüntüle

12
 
12
 
13
 basket_factory = import_module('basket.factory', ['get_or_create_open_basket', 'get_open_basket', 
13
 basket_factory = import_module('basket.factory', ['get_or_create_open_basket', 'get_open_basket', 
14
                                                   'get_or_create_saved_basket', 'get_saved_basket'])
14
                                                   'get_or_create_saved_basket', 'get_saved_basket'])
15
-checkout_forms = import_module('checkout.forms', ['DeliveryAddressForm'])
15
+checkout_forms = import_module('checkout.forms', ['ShippingAddressForm'])
16
 checkout_calculators = import_module('checkout.calculators', ['OrderTotalCalculator'])
16
 checkout_calculators = import_module('checkout.calculators', ['OrderTotalCalculator'])
17
 checkout_utils = import_module('checkout.utils', ['ProgressChecker'])
17
 checkout_utils = import_module('checkout.utils', ['ProgressChecker'])
18
-order_models = import_module('order.models', ['DeliveryAddress', 'Order'])
18
+order_models = import_module('order.models', ['ShippingAddress', 'Order', 'Batch', 'BatchLine', 'BatchLinePrice'])
19
 address_models = import_module('address.models', ['UserAddress'])
19
 address_models = import_module('address.models', ['UserAddress'])
20
 
20
 
21
 class CheckoutSessionData(object):
21
 class CheckoutSessionData(object):
53
     def flush(self):
53
     def flush(self):
54
         self.request.session[self.session_key] = {}
54
         self.request.session[self.session_key] = {}
55
         
55
         
56
-    # Delivery methods    
56
+    # Shipping methods    
57
         
57
         
58
-    def deliver_to_user_address(self, address):
59
-        self._set('delivery', 'user_address_id', address.id)
60
-        self._unset('delivery', 'new_address_fields')
61
-        self._unset('delivery', 'is_default')
58
+    def ship_to_user_address(self, address):
59
+        self._set('shipping', 'user_address_id', address.id)
60
+        self._unset('shipping', 'new_address_fields')
61
+        self._unset('shipping', 'is_default')
62
         
62
         
63
-    def deliver_to_new_address(self, address_fields, is_default=False):
64
-        self._set('delivery', 'new_address_fields', address_fields)
65
-        self._set('delivery', 'is_default', is_default)
66
-        self._unset('delivery', 'user_address_id')
63
+    def ship_to_new_address(self, address_fields, is_default=False):
64
+        self._set('shipping', 'new_address_fields', address_fields)
65
+        self._set('shipping', 'is_default', is_default)
66
+        self._unset('shipping', 'user_address_id')
67
         
67
         
68
     def new_address_fields(self):
68
     def new_address_fields(self):
69
-        return self._get('delivery', 'new_address_fields')
69
+        return self._get('shipping', 'new_address_fields')
70
         
70
         
71
     def user_address_id(self):
71
     def user_address_id(self):
72
-        return self._get('delivery', 'user_address_id')
73
-    
74
-    def should_new_address_be_default(self):
75
-        return self._get('delivery', 'is_default') == True
72
+        return self._get('shipping', 'user_address_id')
76
         
73
         
77
 
74
 
78
 def prev_steps_must_be_complete(view_fn):
75
 def prev_steps_must_be_complete(view_fn):
117
     Need to check here if the user is ready to start the checkout
114
     Need to check here if the user is ready to start the checkout
118
     """
115
     """
119
     if request.user.is_authenticated():
116
     if request.user.is_authenticated():
120
-        return HttpResponseRedirect(reverse('oscar-checkout-delivery-address'))
117
+        return HttpResponseRedirect(reverse('oscar-checkout-shipping-address'))
121
     return render(request, 'checkout/gateway.html', locals())
118
     return render(request, 'checkout/gateway.html', locals())
122
 
119
 
123
 @basket_required
120
 @basket_required
124
-def delivery_address(request):
121
+def shipping_address(request):
125
     """
122
     """
126
-    Handle the selection of a delivery address.
123
+    Handle the selection of a shipping address.
127
     """
124
     """
128
     co_data = CheckoutSessionData(request)
125
     co_data = CheckoutSessionData(request)
129
     if request.method == 'POST':
126
     if request.method == 'POST':
130
         if request.user.is_authenticated and 'address_id' in request.POST:
127
         if request.user.is_authenticated and 'address_id' in request.POST:
131
             address = address_models.UserAddress.objects.get(pk=request.POST['address_id'])
128
             address = address_models.UserAddress.objects.get(pk=request.POST['address_id'])
132
-            if 'action' in request.POST and request.POST['action'] == 'deliver_to':
133
-                # User has selected a previous address to deliver to
134
-                co_data.deliver_to_user_address(address)
129
+            if 'action' in request.POST and request.POST['action'] == 'ship_to':
130
+                # User has selected a previous address to ship to
131
+                co_data.ship_to_user_address(address)
135
                 mark_step_as_complete(request)
132
                 mark_step_as_complete(request)
136
-                return HttpResponseRedirect(reverse('oscar-checkout-delivery-method'))
133
+                return HttpResponseRedirect(reverse('oscar-checkout-shipping-method'))
137
             elif 'action' in request.POST and request.POST['action'] == 'delete':
134
             elif 'action' in request.POST and request.POST['action'] == 'delete':
138
                 address.delete()
135
                 address.delete()
139
                 messages.info(request, "Address deleted from your address book")
136
                 messages.info(request, "Address deleted from your address book")
140
-                return HttpResponseRedirect(reverse('oscar-checkout-delivery-method'))
137
+                return HttpResponseRedirect(reverse('oscar-checkout-shipping-method'))
141
         else:
138
         else:
142
-            form = checkout_forms.DeliveryAddressForm(request.POST)
139
+            form = checkout_forms.ShippingAddressForm(request.POST)
143
             if form.is_valid():
140
             if form.is_valid():
144
                 # Address data is valid - store in session and redirect to next step.
141
                 # Address data is valid - store in session and redirect to next step.
145
                 is_default = False
142
                 is_default = False
146
                 if 'save_as_default' in request.POST and request.POST['save_as_default'] == 'on':
143
                 if 'save_as_default' in request.POST and request.POST['save_as_default'] == 'on':
147
                     is_default = True
144
                     is_default = True
148
-                co_data.deliver_to_new_address(form.clean(), is_default)
145
+                co_data.ship_to_new_address(form.clean(), is_default)
149
                 mark_step_as_complete(request)
146
                 mark_step_as_complete(request)
150
-                return HttpResponseRedirect(reverse('oscar-checkout-delivery-method'))
147
+                return HttpResponseRedirect(reverse('oscar-checkout-shipping-method'))
151
     else:
148
     else:
152
         addr_fields = co_data.new_address_fields()
149
         addr_fields = co_data.new_address_fields()
153
         if addr_fields:
150
         if addr_fields:
154
-            form = checkout_forms.DeliveryAddressForm(addr_fields)
151
+            form = checkout_forms.ShippingAddressForm(addr_fields)
155
         else:
152
         else:
156
-            form = checkout_forms.DeliveryAddressForm()
153
+            form = checkout_forms.ShippingAddressForm()
157
     
154
     
158
     # Add in extra template bindings
155
     # Add in extra template bindings
159
     basket = basket_factory.get_open_basket(request)
156
     basket = basket_factory.get_open_basket(request)
160
     calc = checkout_calculators.OrderTotalCalculator(request)
157
     calc = checkout_calculators.OrderTotalCalculator(request)
161
     order_total = calc.order_total_incl_tax(basket)
158
     order_total = calc.order_total_incl_tax(basket)
162
-    delivery_total_excl_tax = 0
163
-    delivery_total_incl_tax = 0
159
+    shipping_total_excl_tax = 0
160
+    shipping_total_incl_tax = 0
164
     
161
     
165
     # Look up address book data
162
     # Look up address book data
166
     if request.user.is_authenticated():
163
     if request.user.is_authenticated():
167
         addresses = address_models.UserAddress.objects.filter(user=request.user)
164
         addresses = address_models.UserAddress.objects.filter(user=request.user)
168
     
165
     
169
-    return render(request, 'checkout/delivery_address.html', locals())
166
+    return render(request, 'checkout/shipping_address.html', locals())
170
     
167
     
171
     
168
     
172
 @prev_steps_must_be_complete    
169
 @prev_steps_must_be_complete    
173
-def delivery_method(request):
170
+def shipping_method(request):
174
     """
171
     """
175
-    Delivery methods are domain-specific and so need implementing in a 
172
+    Shipping methods are domain-specific and so need implementing in a 
176
     subclass of this class.
173
     subclass of this class.
177
     """
174
     """
178
     mark_step_as_complete(request)
175
     mark_step_as_complete(request)
198
     # Load address data into a blank address model
195
     # Load address data into a blank address model
199
     addr_data = co_data.new_address_fields()
196
     addr_data = co_data.new_address_fields()
200
     if addr_data:
197
     if addr_data:
201
-        delivery_addr = order_models.DeliveryAddress(**addr_data)
198
+        shipping_addr = order_models.ShippingAddress(**addr_data)
202
     addr_id = co_data.user_address_id()
199
     addr_id = co_data.user_address_id()
203
     if addr_id:
200
     if addr_id:
204
-        delivery_addr = address_models.UserAddress.objects.get(pk=addr_id)
201
+        shipping_addr = address_models.UserAddress.objects.get(pk=addr_id)
205
     
202
     
206
     # Calculate order total
203
     # Calculate order total
207
     calc = checkout_calculators.OrderTotalCalculator(request)
204
     calc = checkout_calculators.OrderTotalCalculator(request)
210
     mark_step_as_complete(request)
207
     mark_step_as_complete(request)
211
     return render(request, 'checkout/preview.html', locals())
208
     return render(request, 'checkout/preview.html', locals())
212
 
209
 
213
-@prev_steps_must_be_complete
214
-def submit(request):
215
-    """
216
-    Do several things then redirect to the thank-you page
217
-    """
218
-    co_data = CheckoutSessionData(request)
210
+
211
+class SubmitView(object):
219
     
212
     
220
-    # Save the address data
221
-    addr_data = co_data.new_address_fields()
222
-    if addr_data:
223
-        # A new delivery address has been entered
224
-        delivery_addr = order_models.DeliveryAddress(**addr_data)
225
-        delivery_addr.save()
213
+    def __call__(self, request):
214
+        
215
+        # Set up the instance variables that are needed to place an order
216
+        self.request = request
217
+        self.co_data = CheckoutSessionData(request)
218
+        self.basket = basket_factory.get_open_basket(request)
219
+        
220
+        # All the heavy lifting happens here
221
+        self._place_order()
222
+        
223
+        # Now, reset the states of the basket and checkout 
224
+        self.basket.set_as_submitted()
225
+        self.co_data.flush()
226
+        checkout_utils.ProgressChecker().all_steps_complete(request)
227
+        
228
+        # @todo Save order id in session so thank-you page can load it
229
+        
230
+        return HttpResponseRedirect(reverse('oscar-checkout-thank-you'))
231
+        
232
+    def _place_order(self):
233
+        order = self._create_order_model()
234
+        for line in self.basket.lines.all():
235
+            batch = self._get_or_create_batch_for_line(order, line)
236
+            self._create_line_model(order, batch, line)
237
+        
238
+    def _create_order_model(self):
239
+        calc = checkout_calculators.OrderTotalCalculator(self.request)
240
+        order_data = {'basket': self.basket,
241
+                      'total_incl_tax': calc.order_total_incl_tax(self.basket),
242
+                      'total_excl_tax': calc.order_total_excl_tax(self.basket),
243
+                      'shipping_incl_tax': 0,
244
+                      'shipping_excl_tax': 0,}
245
+        if self.request.user.is_authenticated():
246
+            order_data['user_id'] = self.request.user.id
247
+        order = order_models.Order(**order_data)
248
+        order.save()
249
+        return order
250
+    
251
+    def _create_line_model(self, order, batch, line):
252
+        batch_line = order_models.BatchLine.objects.create(batch=batch, 
253
+                                                           product=line.product, 
254
+                                                           quantity=line.quantity, 
255
+                                                           line_price_excl_tax=line.line_price_excl_tax, 
256
+                                                           line_price_incl_tax=line.line_price_incl_tax)
257
+        order_models.BatchLinePrice.objects.create(line=batch_line, quantity=line.quantity, 
258
+                                                   price_incl_tax=line.unit_price_incl_tax,
259
+                                                   price_excl_tax=line.unit_price_excl_tax)
260
+    
261
+    def _get_or_create_batch_for_line(self, order, line):
262
+         partner = self._get_partner_for_product(line.product)
263
+         shipping_addr = self._get_shipping_address_for_line(line)
264
+         batch,_ = order_models.Batch.objects.get_or_create(order=order, partner=partner, shipping_address=shipping_addr)
265
+         return batch
266
+                
267
+    def _get_partner_for_product(self, product):
268
+        if product.has_stockrecord:
269
+            return product.stockrecord.partner
270
+        raise AttributeError("No partner found for product '%s'" % product)
271
+
272
+    def _get_shipping_address_for_line(self, line):
273
+        try:
274
+            addr = self.shipping_addr
275
+        except AttributeError:
276
+            # No cached version - create a shipping address
277
+            addr_data = self.co_data.new_address_fields()
278
+            addr_id = self.co_data.user_address_id()
279
+            if addr_data:
280
+                addr = self._create_shipping_address_from_form_fields(addr_data)
281
+                self._create_user_address(addr_data)
282
+            elif addr_id:
283
+                addr = self._create_shipping_address_from_user_address(addr_id)
284
+            else:
285
+                raise AttributeError("No shipping address data found")
286
+            
287
+            # Cache it as our default behaviour is to have only one
288
+            # shipping address per order.
289
+            self.shipping_addr = addr
290
+        return addr
291
+            
226
         
292
         
227
-        # Save a new user address
228
-        if request.user.is_authenticated():
229
-            addr_data['user_id'] = request.user.id
293
+    def _create_shipping_address_from_form_fields(self, addr_data):
294
+        shipping_addr = order_models.ShippingAddress(**addr_data)
295
+        shipping_addr.save() 
296
+        return shipping_addr
297
+    
298
+    def _create_user_address(self, addr_data):
299
+        """
300
+        For signed-in users, we create a user address model which will go 
301
+        into their address book.
302
+        """
303
+        if self.request.user.is_authenticated():
304
+            addr_data['user_id'] = self.request.user.id
230
             user_addr = address_models.UserAddress(**addr_data)
305
             user_addr = address_models.UserAddress(**addr_data)
231
-            # Check that this address isn't already in the db
306
+            # Check that this address isn't already in the db as we don't want
307
+            # to fill up the customer address book with duplicate addresses
232
             try:
308
             try:
233
                 duplicate_addr = address_models.UserAddress.objects.get(hash=user_addr.generate_hash())
309
                 duplicate_addr = address_models.UserAddress.objects.get(hash=user_addr.generate_hash())
234
             except ObjectDoesNotExist:
310
             except ObjectDoesNotExist:
235
-                if co_data.should_new_address_be_default():
236
-                    user_addr.is_primary = True 
237
                 user_addr.save()
311
                 user_addr.save()
238
-            
239
-    addr_id = co_data.user_address_id()
240
-    if addr_id:
241
-        # A previously used address has been selected.  We need to convert it
242
-        # to a delivery address and save it
243
-        address = address_models.UserAddress.objects.get(pk=addr_id)
244
-        delivery_addr = order_models.DeliveryAddress()
245
-        address.populate_alternative_model(delivery_addr)
246
-        delivery_addr.save()
247
     
312
     
248
-    # Save the order model
249
-    calc = checkout_calculators.OrderTotalCalculator(request)
250
-    basket = basket_factory.get_open_basket(request)
251
-    order_data = {'basket': basket,
252
-                  'total_incl_tax': calc.order_total_incl_tax(basket),
253
-                  'total_excl_tax': calc.order_total_excl_tax(basket),
254
-                  'shipping_incl_tax': 0,
255
-                  'shipping_excl_tax': 0,}
256
-    if request.user.is_authenticated():
257
-        order_data['user_id'] = request.user.id
258
-    order = order_models.Order(**order_data).save()
259
-    
260
-    # @todo set basket as submitted
261
-    basket.set_as_submitted()
262
-    
263
-    # @todo unset all session data
264
-    co_data.flush()
265
-    
266
-    # @todo Save order id in session so thank-you page can load it
267
-    checkout_utils.ProgressChecker().all_steps_complete(request)
268
-    return HttpResponseRedirect(reverse('oscar-checkout-thank-you'))
313
+    def _create_shipping_address_from_user_address(self, addr_id):
314
+        address = address_models.UserAddress.objects.get(pk=addr_id)
315
+        # Increment the number of orders to help determine popularity of orders 
316
+        address.num_orders += 1
317
+        address.save()
318
+        
319
+        shipping_addr = order_models.ShippingAddress()
320
+        address.populate_alternative_model(shipping_addr)
321
+        shipping_addr.save()
322
+        return shipping_addr
269
 
323
 
270
 
324
 
271
 def thank_you(request):
325
 def thank_you(request):
272
-    return render(request, 'checkout/thank_you.html', locals())
326
+    return render(request, 'checkout/thank_you.html', locals())

+ 7
- 7
oscar/order/abstract_models.py Dosyayı Görüntüle

32
     def __unicode__(self):
32
     def __unicode__(self):
33
         return "#%d (customer: %s, amount: %.2f)" % (self.number, self.customer.username, self.total_incl_tax)
33
         return "#%d (customer: %s, amount: %.2f)" % (self.number, self.customer.username, self.total_incl_tax)
34
 
34
 
35
+
35
 class AbstractBatch(models.Model):
36
 class AbstractBatch(models.Model):
36
     """
37
     """
37
     A batch of items from a single fulfillment partner
38
     A batch of items from a single fulfillment partner
40
     """
41
     """
41
     order = models.ForeignKey('order.Order')
42
     order = models.ForeignKey('order.Order')
42
     partner = models.ForeignKey('stock.Partner')
43
     partner = models.ForeignKey('stock.Partner')
43
-    delivery_method = models.CharField(_("Delivery method"), max_length=128)
44
-    # Not all batches are actually delivered (such as downloads)
45
-    delivery_address = models.ForeignKey('order.DeliveryAddress', null=True, blank=True)
46
-    # Whether the batch should be dispatched in one go, or as they become available
47
-    dispatch_option = models.CharField(_("Dispatch option"), max_length=128, null=True, blank=True)
44
+    # Not all batches are actually shipped (such as downloads)
45
+    shipping_address = models.ForeignKey('order.ShippingAddress', null=True, blank=True)
46
+    shipping_method = models.CharField(_("Shipping method"), max_length=128, null=True, blank=True)
48
     
47
     
49
     def get_num_items(self):
48
     def get_num_items(self):
50
         return len(self.lines.all())
49
         return len(self.lines.all())
56
     def __unicode__(self):
55
     def __unicode__(self):
57
         return "%s batch for order #%d" % (self.partner.name, self.order.number)
56
         return "%s batch for order #%d" % (self.partner.name, self.order.number)
58
         
57
         
58
+        
59
 class AbstractBatchLine(models.Model):
59
 class AbstractBatchLine(models.Model):
60
     """
60
     """
61
     A line within a batch.
61
     A line within a batch.
96
     quantity = models.PositiveIntegerField(default=1)
96
     quantity = models.PositiveIntegerField(default=1)
97
     price_incl_tax = models.DecimalField(decimal_places=2, max_digits=12)
97
     price_incl_tax = models.DecimalField(decimal_places=2, max_digits=12)
98
     price_excl_tax = models.DecimalField(decimal_places=2, max_digits=12)
98
     price_excl_tax = models.DecimalField(decimal_places=2, max_digits=12)
99
-    delivery_incl_tax = models.DecimalField(decimal_places=2, max_digits=12, default=0)
100
-    delivery_excl_tax = models.DecimalField(decimal_places=2, max_digits=12, default=0)
99
+    shipping_incl_tax = models.DecimalField(decimal_places=2, max_digits=12, default=0)
100
+    shipping_excl_tax = models.DecimalField(decimal_places=2, max_digits=12, default=0)
101
     
101
     
102
     class Meta:
102
     class Meta:
103
         abstract = True
103
         abstract = True

+ 2
- 2
oscar/order/admin.py Dosyayı Görüntüle

2
 from oscar.order.models import *
2
 from oscar.order.models import *
3
 
3
 
4
 class BatchAdmin(admin.ModelAdmin):
4
 class BatchAdmin(admin.ModelAdmin):
5
-    list_display = ('order', 'partner', 'get_num_items', 'delivery_method')
5
+    list_display = ('order', 'partner', 'get_num_items', 'shipping_method')
6
 
6
 
7
 class BatchLineAdmin(admin.ModelAdmin):
7
 class BatchLineAdmin(admin.ModelAdmin):
8
     list_display = ('batch', 'product', 'quantity')
8
     list_display = ('batch', 'product', 'quantity')
10
 admin.site.register(Order)
10
 admin.site.register(Order)
11
 admin.site.register(BillingAddress)
11
 admin.site.register(BillingAddress)
12
 admin.site.register(Batch, BatchAdmin)
12
 admin.site.register(Batch, BatchAdmin)
13
-admin.site.register(DeliveryAddress)
13
+admin.site.register(ShippingAddress)
14
 admin.site.register(BatchLine, BatchLineAdmin)
14
 admin.site.register(BatchLine, BatchLineAdmin)
15
 admin.site.register(BatchLinePrice)
15
 admin.site.register(BatchLinePrice)
16
 admin.site.register(BatchLineEvent)
16
 admin.site.register(BatchLineEvent)

+ 2
- 2
oscar/order/models.py Dosyayı Görüntüle

4
 from django.db import models
4
 from django.db import models
5
 
5
 
6
 from oscar.order.abstract_models import *
6
 from oscar.order.abstract_models import *
7
-from oscar.address.abstract_models import AbstractAddress, AbstractDeliveryAddress, AbstractBillingAddress
7
+from oscar.address.abstract_models import AbstractAddress, AbstractShippingAddress, AbstractBillingAddress
8
 
8
 
9
 class Order(AbstractOrder):
9
 class Order(AbstractOrder):
10
     pass
10
     pass
12
 class Batch(AbstractBatch):
12
 class Batch(AbstractBatch):
13
     pass
13
     pass
14
 
14
 
15
-class DeliveryAddress(AbstractDeliveryAddress):
15
+class ShippingAddress(AbstractShippingAddress):
16
     pass
16
     pass
17
 
17
 
18
 class BillingAddress(AbstractBillingAddress):
18
 class BillingAddress(AbstractBillingAddress):

+ 2
- 2
oscar/order/tests.py Dosyayı Görüntüle

4
 from oscar.basket.models import Basket
4
 from oscar.basket.models import Basket
5
 from oscar.order.models import *
5
 from oscar.order.models import *
6
 
6
 
7
-class DeliveryAddressTest(unittest.TestCase):
7
+class ShippingAddressTest(unittest.TestCase):
8
     
8
     
9
     def setUp(self):
9
     def setUp(self):
10
         pass
10
         pass
11
     
11
     
12
     def test_titleless_salutation_is_stripped(self):
12
     def test_titleless_salutation_is_stripped(self):
13
-        a = DeliveryAddress.objects.create(last_name='Barrington', line1="75 Smith Road", postcode="N4 8TY")
13
+        a = ShippingAddress.objects.create(last_name='Barrington', line1="75 Smith Road", postcode="N4 8TY")
14
         self.assertEquals("Barrington", a.get_salutation())
14
         self.assertEquals("Barrington", a.get_salutation())
15
     
15
     
16
         
16
         

+ 0
- 1
oscar/services.py Dosyayı Görüntüle

37
                 # Passing classes to __import__ here does not actually filter out the 
37
                 # Passing classes to __import__ here does not actually filter out the 
38
                 # classes, we need to iterate through and assign them individually.
38
                 # classes, we need to iterate through and assign them individually.
39
                 mod = new_module(real_app)
39
                 mod = new_module(real_app)
40
-                print real_app
41
                 imported_mod = __import__(real_app, fromlist=classes)
40
                 imported_mod = __import__(real_app, fromlist=classes)
42
                 for classname in classes:
41
                 for classname in classes:
43
                     mod.__setattr__(classname, getattr(imported_mod, classname))
42
                     mod.__setattr__(classname, getattr(imported_mod, classname))

Loading…
İptal
Kaydet