Explorar el Código

Added order detail page with line batch actions

master
David Winterbottom hace 14 años
padre
commit
70e93724c4

+ 4
- 2
oscar/apps/dashboard/app.py Ver fichero

@@ -10,12 +10,14 @@ class DashboardApplication(Application):
10 10
     name = 'dashboard'
11 11
     
12 12
     index_view = views.IndexView
13
-    orders_view = views.OrderListView
13
+    order_list_view = views.OrderListView
14
+    order_detail_view = views.OrderDetailView
14 15
 
15 16
     def get_urls(self):
16 17
         urlpatterns = patterns('',
17 18
             url(r'^$', self.index_view.as_view(), name='index'),
18
-            url(r'^orders/$', self.orders_view.as_view(), name='orders'),
19
+            url(r'^orders/$', self.order_list_view.as_view(), name='orders'),
20
+            url(r'^orders/(?P<number>[-\w]+)/$', self.order_detail_view.as_view(), name='order'),
19 21
         )
20 22
         return self.post_process_urls(urlpatterns)
21 23
 

+ 20
- 2
oscar/apps/dashboard/tests.py Ver fichero

@@ -5,6 +5,9 @@ from django.test.client import Client
5 5
 from django.core.urlresolvers import reverse
6 6
 from django.contrib.auth.models import User
7 7
 
8
+from oscar.test.helpers import create_order
9
+from oscar.apps.dashboard.forms import OrderSearchForm
10
+
8 11
 
9 12
 class ViewTests(TestCase):
10 13
 
@@ -42,6 +45,21 @@ class DashboardViewTests(StaffViewTests):
42 45
 class OrderListTests(StaffViewTests):
43 46
 
44 47
     def test_searching_for_valid_order_number_redirects_to_order_page(self):
45
-        pass
46
-
48
+        order = create_order()
49
+        fields = OrderSearchForm.base_fields.keys()
50
+        pairs = dict(zip(fields, ['']*len(fields)))
51
+        pairs['order_number'] = order.number
52
+        pairs['response_format'] = 'html'
53
+        url = '%s?%s' % (reverse('dashboard:orders'), '&'.join(['%s=%s' % (k,v) for k,v in pairs.items()]))
54
+        response = self.client.get(url)
55
+        self.assertEqual(httplib.FOUND, response.status_code)
56
+
57
+
58
+class OrderDetailTests(StaffViewTests):
59
+
60
+    def test_order_detail_page_contains_order(self):
61
+        order = create_order()
62
+        url = reverse('dashboard:order', kwargs={'number': order.number})
63
+        response = self.client.get(url)
64
+        self.assertTrue('order' in response.context)
47 65
 

+ 65
- 4
oscar/apps/dashboard/views.py Ver fichero

@@ -1,16 +1,18 @@
1 1
 import csv
2 2
 
3
-from django.views.generic import TemplateView, ListView
4 3
 from django.contrib import messages
5
-from django.utils.datastructures import SortedDict
6
-from django.template.defaultfilters import date as format_date
4
+from django.core.urlresolvers import reverse
7 5
 from django.db.models.loading import get_model
8 6
 from django.http import HttpResponse, HttpResponseRedirect
9
-from django.core.urlresolvers import reverse
7
+from django.shortcuts import get_object_or_404
8
+from django.template.defaultfilters import date as format_date
9
+from django.utils.datastructures import SortedDict
10
+from django.views.generic import TemplateView, ListView, DetailView
10 11
 
11 12
 from oscar.apps.dashboard.forms import OrderSearchForm
12 13
 
13 14
 Order = get_model('order', 'Order')
15
+Line = get_model('order', 'Line')
14 16
 
15 17
 
16 18
 class IndexView(TemplateView):
@@ -27,6 +29,16 @@ class OrderListView(ListView):
27 29
     description = ''
28 30
     actions = ('download_selected_orders',)
29 31
 
32
+    def get(self, request, *args, **kwargs):
33
+        if 'order_number' in request.GET:
34
+            try:
35
+                order = Order.objects.get(number=request.GET['order_number'])
36
+            except Order.DoesNotExist:
37
+                pass
38
+            else:
39
+                return HttpResponseRedirect(reverse('dashboard:order', kwargs={'number': order.number}))
40
+        return super(OrderListView, self).get(request, *args, **kwargs)
41
+
30 42
     def get_queryset(self):
31 43
         """
32 44
         Build the queryset for this list and also update the title that 
@@ -164,3 +176,52 @@ class OrderListView(ListView):
164 176
             encoded_values = [unicode(value).encode('utf8') for value in row.values()]
165 177
             writer.writerow(encoded_values)
166 178
         return response
179
+
180
+
181
+class OrderDetailView(DetailView):
182
+    model = Order
183
+    context_object_name = 'order'
184
+    template_name = 'dashboard/orders/order_detail.html'
185
+    order_actions = ()
186
+    line_actions = ('change_line_statuses',)
187
+
188
+    def get_object(self):
189
+        return get_object_or_404(self.model, number=self.kwargs['number'])
190
+
191
+    def post(self, request, *args, **kwargs):
192
+        self.object = self.get_object()
193
+        order = self.object
194
+
195
+        # Look for line-level action
196
+        line_action = request.POST.get('line-action', '').lower()
197
+        if line_action:
198
+            if line_action not in self.line_actions:
199
+                messages.error(self.request, "Invalid action")
200
+                return self.reload_page_response()
201
+            else:
202
+                line_ids = request.POST.getlist('selected_line')
203
+                lines = order.lines.filter(id__in=line_ids)
204
+                if lines.count() == 0:
205
+                    messages.error(self.request, "You must select some lines to act on")
206
+                    return self.reload_page_response()
207
+                return getattr(self, line_action)(request, order, lines)
208
+
209
+        messages.error(request, "No valid action submitted")
210
+        return self.reload_page_response()
211
+
212
+    def reload_page_response(self):
213
+        return HttpResponseRedirect(reverse('dashboard:order', kwargs={'number': self.object.number}))
214
+
215
+    def change_line_statuses(self, request, order, lines):
216
+        new_status = request.POST['new_status'].strip()
217
+        if not new_status:
218
+            messages.error(request, "The new status '%s' is not valid" % new_status)
219
+            return self.reload_page_response()
220
+        for line in lines:
221
+            messages.info(request, "Line %d changed from '%s' to '%s'" % (
222
+                line.id, line.status, new_status))
223
+            line.status = new_status
224
+            line.save()
225
+        return self.reload_page_response()
226
+
227
+

+ 1
- 1
oscar/apps/order/abstract_models.py Ver fichero

@@ -103,7 +103,7 @@ class AbstractOrder(models.Model):
103 103
     
104 104
     @property
105 105
     def num_items(self):
106
-        u"""
106
+        """
107 107
         Returns the number of items in this order.
108 108
         """
109 109
         num_items = 0

+ 4
- 0
oscar/templates/dashboard/index.html Ver fichero

@@ -3,5 +3,9 @@
3 3
 {% block content %}
4 4
 
5 5
 <h1>Dashboard</h1>
6
+<p>What do you want to do?</p>
7
+<ul>
8
+    <li><a href="{% url dashboard:orders %}">Manage orders</a></li>
9
+</ul>
6 10
 
7 11
 {% endblock %}

+ 173
- 0
oscar/templates/dashboard/orders/order_detail.html Ver fichero

@@ -0,0 +1,173 @@
1
+{% extends "layout.html" %}
2
+{% load currency_filters %}
3
+
4
+{% block title %}
5
+Order {{ order.number }}
6
+{% endblock %}
7
+
8
+{% block header %}
9
+    <h2>Order {{ order.number }}</h2>
10
+{% endblock header %}
11
+
12
+{% block content %}
13
+
14
+<h2>Order information</h2>
15
+<table>
16
+    <tr>
17
+        <th>Date of purchase</th>
18
+        <th>Time of purchase</th>
19
+        <th>Status</th>
20
+    </tr>
21
+    <tr>
22
+        <td>{{ order.date_placed|date:"d/m/y" }}</td>
23
+        <td>{{ order.date_placed|date:"H:s" }}</td>
24
+        <td>{{ order.status|default:"N/A" }}</td>
25
+    </tr>
26
+</table>
27
+
28
+<h2>Customer</h2>
29
+{% if order.user %}
30
+<table>
31
+    <tr>
32
+        <th>Username</th>
33
+        <td>{{ order.user.username }}</td>
34
+    </tr>
35
+    <tr>
36
+        <th>Name</th>
37
+        <td>{{ order.user.get_full_name|default:"-" }}</td>
38
+    </tr>
39
+    <tr>
40
+        <th>Email address</th>
41
+        <td>{{ order.user.email|default:"-" }}</td>
42
+    </tr>
43
+</table>
44
+{% else %}
45
+<p>Customer checked out anonymously.</p>
46
+{% endif %}
47
+
48
+<h2>Payment</h2>
49
+{% with sources=order.sources.all %}
50
+{% if sources %}
51
+<table>     
52
+    <thead>  
53
+        <tr>
54
+            <th>Source</th>
55
+            <th>Allocation</th>
56
+            <th>Amount debited</th>
57
+            <th>Amount refunded</th>
58
+        </tr>  
59
+    </thead>	
60
+    <tbody> 
61
+        {% for source in sources %}
62
+        <tr>
63
+            <td>{{ source.source_type }}</td>
64
+            <td>{{ source.amount_allocated|currency }}</td>
65
+            <td>{{ source.amount_debited|currency }}</td>
66
+            <td>{{ source.amount_refunded|currency }}</td>
67
+        </tr>
68
+        {% endfor %}
69
+    </tbody>	
70
+</table>
71
+{% else %}
72
+<p>No payment sources</p>
73
+{% endif %}
74
+{% endwith %}
75
+
76
+{% if order.billing_address %}
77
+<h3>Billing address</h3>
78
+<p>
79
+{% for field in order.billing_address.active_address_fields %}
80
+{{ field }}<br/>
81
+{% endfor %}
82
+</p>
83
+{% endif %}
84
+
85
+{% if order.shipping_address %}
86
+<h2>Shipping</h2>
87
+<p>
88
+{% for field in order.shipping_address.active_address_fields %}
89
+{{ field }}<br/>
90
+{% endfor %}
91
+</p>
92
+{% endif %}
93
+
94
+<h2>Discounts</h2>
95
+{% with discounts=order.discounts.all %}
96
+{% if discounts %}
97
+<table>
98
+    <tr>
99
+        <th>Voucher code</th>
100
+        <th>Offer name</th>
101
+        <th>Amount</th>
102
+    </tr>
103
+    {% for discount in discounts %}
104
+    <tr>
105
+        <td>{{ discount.voucher_code }}</td>
106
+        <td>{{ discount.offer.name }}</td>
107
+        <td>{{ discount.amount|currency}}</td>
108
+    </tr>
109
+    {% endfor %}
110
+{% else %}
111
+<p>No discounts were applied in this order.</p>
112
+{% endif %}
113
+{% endwith %}
114
+
115
+<h2>Items ordered</h2>
116
+<form action="." method="post">
117
+{% csrf_token %}
118
+<table>
119
+    <tr>
120
+        <th>Select</th>
121
+        <th>Product</th>
122
+        <th>Status</th>
123
+        <th>Supplier</th>
124
+        <th>Supplier SKU</th>
125
+        <th>Est. delivery date</th>
126
+        <th>Price (after discounts)</th>
127
+        <th>Price (before discounts)</th>
128
+        <th>Actions</th>
129
+    </tr>
130
+    {% for line in order.lines.all %}
131
+    <tr>
132
+        <td><input type="checkbox" name="selected_line" value="{{ line.id }}" /></td>
133
+        <td>{{ line.title }}</td>
134
+        <td>{{ line.status|default:"-" }}</td>
135
+        <td>{{ line.partner_name }}</td>
136
+        <td>{{ line.partner_sku }}</td>
137
+        <td>{{ line.est_dispatch_date }}</td>
138
+        <td>{{ line.line_price_before_discounts_incl_tax|currency }}</td>
139
+        <td>{{ line.line_price_incl_tax|currency }}</td>
140
+        <td>
141
+            <a href="">Edit</a>
142
+        </td>
143
+    </tr>
144
+    {% endfor %}
145
+    <tr>
146
+        <td colspan="6"></td>
147
+        <td>Discount</td>
148
+        <td>{{ order.total_discount_incl_tax|currency }}</td>
149
+    </tr>
150
+    <tr>
151
+        <td colspan="6"></td>
152
+        <td>Shipping charge</td>
153
+        <td>{{ order.shipping_incl_tax|currency }}</td>
154
+    </tr>
155
+    <tr>
156
+        <td colspan="6"></td>
157
+        <td>Total</td>
158
+        <td>{{ order.total_incl_tax|currency }}</td>
159
+    </tr>
160
+</table>
161
+
162
+<p>With selected lines:</p>
163
+<ul>
164
+    <li><label><input type="radio" name="line-action" value="change_line_statuses" /> Change status to</label>
165
+    <input type="text" name="new_status" /> 
166
+    </li>
167
+</ul>
168
+<input type="submit" value="Go!" />
169
+</form>
170
+
171
+<h2>Notes</h2>
172
+
173
+{% endblock content %}

+ 1
- 1
oscar/templates/dashboard/orders/order_list.html Ver fichero

@@ -49,7 +49,7 @@
49 49
         <td>{{ order.shipping_address }}</td>
50 50
         <td>{{ order.billing_address }}</td>
51 51
         <td>
52
-            <a href="">View</a>
52
+            <a href="{% url dashboard:order order.number %}">View</a>
53 53
         </td>
54 54
     </tr>
55 55
     {% endfor %}

Loading…
Cancelar
Guardar