瀏覽代碼

Corrected bug in session keys for saving objects

master
David Winterbottom 13 年之前
父節點
當前提交
21e15e4bfa

+ 3
- 0
oscar/apps/dashboard/offers/app.py 查看文件

@@ -18,6 +18,7 @@ class OffersDashboardApplication(Application):
18 18
     benefit_view = views.OfferBenefitView
19 19
     preview_view = views.OfferPreviewView
20 20
     delete_view = views.OfferDeleteView
21
+    detail_view = views.OfferDetailView
21 22
 
22 23
     def get_urls(self):
23 24
         urlpatterns = patterns('',
@@ -34,6 +35,8 @@ class OffersDashboardApplication(Application):
34 35
             url(r'^(?P<pk>\d+)/preview/$', self.preview_view.as_view(update=True), name='offer-preview'),
35 36
             # Delete
36 37
             url(r'^(?P<pk>\d+)/delete/$', self.delete_view.as_view(), name='offer-delete'),
38
+            # Stats
39
+            url(r'^(?P<pk>\d+)/$', self.detail_view.as_view(), name='offer-detail'),
37 40
         )
38 41
         return self.post_process_urls(urlpatterns)
39 42
 

+ 4
- 4
oscar/apps/dashboard/offers/tests.py 查看文件

@@ -50,25 +50,25 @@ class OfferCreationTests(ClientTestCase):
50 50
                                              'description': 'offers are nice',
51 51
                                              'start_date': '2012-01-01',
52 52
                                              'end_date': '2013-01-01'})
53
-        self.assertIsRedirect(response)
53
+        self.assertIsRedirect(response, reverse('dashboard:offer-condition'))
54 54
 
55 55
         # Condition
56 56
         response = self.client.post(reverse('dashboard:offer-condition'),
57 57
                                             {'range': self.range.id,
58 58
                                              'type': 'Count',
59 59
                                              'value': '3',})
60
-        self.assertIsRedirect(response)
60
+        self.assertIsRedirect(response, reverse('dashboard:offer-benefit'))
61 61
 
62 62
         # Benefit
63 63
         response = self.client.post(reverse('dashboard:offer-benefit'),
64 64
                                             {'range': self.range.id,
65 65
                                              'type': 'Multibuy',
66 66
                                              'value': '1',})
67
-        self.assertIsRedirect(response)
67
+        self.assertIsRedirect(response, reverse('dashboard:offer-preview'))
68 68
 
69 69
         # Preview
70 70
         response = self.client.post(reverse('dashboard:offer-preview'), {})
71
-        self.assertIsRedirect(response)
71
+        self.assertIsRedirect(response, reverse('dashboard:offer-list'))
72 72
 
73 73
         offers = ConditionalOffer.objects.all()
74 74
         self.assertEqual(1, len(offers))

+ 26
- 10
oscar/apps/dashboard/offers/views.py 查看文件

@@ -1,4 +1,4 @@
1
-from django.views.generic import ListView, FormView, DeleteView
1
+from django.views.generic import ListView, FormView, DeleteView, DetailView
2 2
 from django.db.models.loading import get_model
3 3
 from django.core.urlresolvers import reverse
4 4
 from django.contrib import messages
@@ -9,6 +9,7 @@ from oscar.core.loading import get_classes
9 9
 
10 10
 ConditionalOffer = get_model('offer', 'ConditionalOffer')
11 11
 Condition= get_model('offer', 'Condition')
12
+OrderDiscount = get_model('order', 'OrderDiscount')
12 13
 Benefit = get_model('offer', 'Benefit')
13 14
 MetaDataForm, ConditionForm, BenefitForm, PreviewForm = get_classes('dashboard.offers.forms', [
14 15
     'MetaDataForm', 'ConditionForm', 'BenefitForm', 'PreviewForm'])
@@ -53,30 +54,34 @@ class OfferWizardStepView(FormView):
53 54
             return True
54 55
         return self.previous_view.is_valid(self, request)
55 56
 
57
+    def _key(self, step_name=None, is_object=False):
58
+        key = step_name if step_name else self.step_name
59
+        if self.update:
60
+            key += str(self.offer.id)
61
+        if is_object:
62
+            key += '_obj'
63
+        return key
64
+
56 65
     def _store_form_kwargs(self, form):
57 66
         session_data = self.request.session.setdefault(self.wizard_name, {})
58 67
         form_kwargs = {'data': form.cleaned_data.copy()}
59
-        session_data[self.step_name] = form_kwargs
68
+        session_data[self._key()] = form_kwargs
60 69
         self.request.session.save()
61 70
 
62 71
     def _fetch_form_kwargs(self, step_name=None):
63 72
         if not step_name:
64 73
             step_name = self.step_name
65 74
         session_data = self.request.session.setdefault(self.wizard_name, {})
66
-        return session_data.get(step_name, {})
75
+        return session_data.get(self._key(step_name), {})
67 76
 
68 77
     def _store_object(self, form):
69 78
         session_data = self.request.session.setdefault(self.wizard_name, {})
70
-        session_data[self.step_name + '_obj'] = form.save(commit=False)
79
+        session_data[self._key(is_object=True)] = form.save(commit=False)
71 80
         self.request.session.save()
72 81
 
73
-    def _fetch_object(self, step_name, request=None):
74
-        # We pass in the session as part of the checks on previous steps, as in those
75
-        # cases we're using an
76
-        if not request:
77
-            request = self.request
82
+    def _fetch_object(self, step_name):
78 83
         session_data = self.request.session.setdefault(self.wizard_name, {})
79
-        return session_data.get(step_name + '_obj', None)
84
+        return session_data.get(self._key(step_name, is_object=True), None)
80 85
 
81 86
     def _flush_session(self):
82 87
         self.request.session[self.wizard_name] = {}
@@ -221,3 +226,14 @@ class OfferDeleteView(DeleteView):
221 226
     def get_success_url(self):
222 227
         messages.success(self.request, "Offer deleted!")
223 228
         return reverse('dashboard:offer-list')
229
+
230
+
231
+class OfferDetailView(DetailView):
232
+    model = ConditionalOffer
233
+    template_name = 'dashboard/offers/offer_detail.html'
234
+    context_object_name = 'offer'
235
+
236
+    def get_context_data(self, **kwargs):
237
+        ctx = super(OfferDetailView, self).get_context_data(**kwargs)
238
+        ctx['order_discounts'] = OrderDiscount.objects.filter(offer_id=self.object.id).order_by('-id')
239
+        return ctx

+ 2
- 2
oscar/apps/offer/admin.py 查看文件

@@ -15,13 +15,13 @@ class BenefitAdmin(admin.ModelAdmin):
15 15
 class ConditionalOfferAdmin(admin.ModelAdmin):
16 16
     list_display = ('name', 'offer_type', 'start_date', 'end_date', 'condition', 'benefit', 'total_discount')
17 17
     list_filter = ('offer_type',)
18
-    readonly_fields = ('total_discount',)
18
+    readonly_fields = ('total_discount', 'num_orders')
19 19
     fieldsets = (
20 20
         (None, {
21 21
             'fields': ('name', 'description', 'offer_type', 'condition', 'benefit', 'start_date', 'end_date', 'priority')
22 22
         }),
23 23
         ('Usage', {
24
-            'fields': ('total_discount',)
24
+            'fields': ('total_discount', 'num_orders')
25 25
         }),
26 26
     )
27 27
 

+ 9
- 3
oscar/apps/offer/models.py 查看文件

@@ -52,6 +52,7 @@ class ConditionalOffer(models.Model):
52 52
 
53 53
     # We track some information on usage
54 54
     total_discount = models.DecimalField(decimal_places=2, max_digits=12, default=Decimal('0.00'))
55
+    num_orders = models.PositiveIntegerField(default=0)
55 56
     
56 57
     date_created = models.DateTimeField(auto_now_add=True)
57 58
 
@@ -82,7 +83,7 @@ class ConditionalOffer(models.Model):
82 83
         return self._proxy_condition().is_satisfied(basket)
83 84
         
84 85
     def apply_benefit(self, basket):
85
-        u"""
86
+        """
86 87
         Applies the benefit to the given basket and returns the discount.
87 88
         """
88 89
         if not self.is_condition_satisfied(basket):
@@ -96,7 +97,7 @@ class ConditionalOffer(models.Model):
96 97
         return self._voucher        
97 98
         
98 99
     def _proxy_condition(self):
99
-        u"""
100
+        """
100 101
         Returns the appropriate proxy model for the condition
101 102
         """
102 103
         field_dict = self.condition.__dict__
@@ -111,7 +112,7 @@ class ConditionalOffer(models.Model):
111 112
         return self.condition
112 113
     
113 114
     def _proxy_benefit(self):
114
-        u"""
115
+        """
115 116
         Returns the appropriate proxy model for the condition
116 117
         """
117 118
         field_dict = self.benefit.__dict__
@@ -126,6 +127,11 @@ class ConditionalOffer(models.Model):
126 127
         elif self.benefit.type == self.benefit.FIXED_PRICE:
127 128
             return FixedPriceBenefit(**field_dict)
128 129
         return self.benefit
130
+
131
+    def record_usage(self, discount):
132
+        self.num_orders += 1
133
+        self.total_discount += discount
134
+        self.save()
129 135
         
130 136
 
131 137
 class Condition(models.Model):

+ 7
- 9
oscar/apps/offer/receivers.py 查看文件

@@ -1,10 +1,12 @@
1 1
 from django.dispatch import receiver
2 2
 from django.db.models.signals import m2m_changed, post_save
3
+from django.db.models import get_model
3 4
 
4
-from oscar.core.loading import import_module
5 5
 from oscar.apps.basket.abstract_models import AbstractBasket
6
-import_module('voucher.models', ['Voucher'], locals())
7
-import_module('order.models', ['OrderDiscount'], locals())
6
+Voucher = get_model('voucher', 'Voucher')
7
+OrderDiscount = get_model('order', 'OrderDiscount')
8
+ConditionalOffer = get_model('offer', 'ConditionalOffer')
9
+
8 10
 
9 11
 @receiver(m2m_changed)
10 12
 def receive_basket_voucher_change(sender, **kwargs):
@@ -15,6 +17,7 @@ def receive_basket_voucher_change(sender, **kwargs):
15 17
         voucher.num_basket_additions += 1
16 18
         voucher.save()
17 19
 
20
+
18 21
 @receiver(post_save, sender=OrderDiscount)        
19 22
 def receive_order_discount_save(sender, instance, **kwargs):
20 23
     # Record the amount of discount against the appropriate offers
@@ -24,9 +27,4 @@ def receive_order_discount_save(sender, instance, **kwargs):
24 27
         discount.voucher.total_discount += discount.amount
25 28
         discount.voucher.save()
26 29
     if discount.offer:
27
-        discount.offer.total_discount += discount.amount
28
-        discount.offer.save()
29
-    
30
-    
31
-        
32
-    
30
+        discount.offer.record_usage(discount.amount)

+ 1
- 1
oscar/templates/dashboard/offers/offer_delete.html 查看文件

@@ -41,7 +41,7 @@ Delete offer #{{ offer.id }}? | Offer management | {{ block.super }}
41 41
 	</table>
42 42
 
43 43
 	<div class="form-actions">
44
-		<button class="btn btn-primary" type="submit">Delete</button> or
44
+		<button class="btn btn-danger" type="submit">Delete</button> or
45 45
 		<a href="{% url dashboard:offer-list %}">cancel</a>
46 46
 	</div>
47 47
 </form>

+ 8
- 2
oscar/test/__init__.py 查看文件

@@ -4,6 +4,7 @@ from contextlib import contextmanager
4 4
 from django.test import TestCase
5 5
 from django.test.client import Client
6 6
 from django.contrib.auth.models import User
7
+from purl import URL
7 8
 
8 9
 
9 10
 @contextmanager
@@ -31,7 +32,7 @@ class ClientTestCase(TestCase):
31 32
         self.client = Client()
32 33
         if not self.is_anonymous:
33 34
             self.user = self.create_user()
34
-            self.client.login(username=self.username, 
35
+            self.client.login(username=self.username,
35 36
                               password=self.password)
36 37
 
37 38
     def create_user(self):
@@ -43,9 +44,14 @@ class ClientTestCase(TestCase):
43 44
         user.save()
44 45
         return user
45 46
 
46
-    def assertIsRedirect(self, response):
47
+    def assertIsRedirect(self, response, expected_url=None):
47 48
         self.assertTrue(response.status_code in (httplib.FOUND,
48 49
                                                  httplib.MOVED_PERMANENTLY))
50
+        if expected_url:
51
+            location = URL.from_string(response['Location'])
52
+            self.assertEqual(expected_url, location.path())
53
+
54
+
49 55
 
50 56
     def assertIsOk(self, response):
51 57
         self.assertEqual(httplib.OK, response.status_code)

+ 1
- 0
testing-reqs.txt 查看文件

@@ -12,3 +12,4 @@ mock==0.7.0
12 12
 twill==0.9
13 13
 PyHamcrest==1.6
14 14
 South==0.7.3
15
+purl==0.3.2

Loading…
取消
儲存