瀏覽代碼

Corrected bug in session keys for saving objects

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

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

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

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

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

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

1
-from django.views.generic import ListView, FormView, DeleteView
1
+from django.views.generic import ListView, FormView, DeleteView, DetailView
2
 from django.db.models.loading import get_model
2
 from django.db.models.loading import get_model
3
 from django.core.urlresolvers import reverse
3
 from django.core.urlresolvers import reverse
4
 from django.contrib import messages
4
 from django.contrib import messages
9
 
9
 
10
 ConditionalOffer = get_model('offer', 'ConditionalOffer')
10
 ConditionalOffer = get_model('offer', 'ConditionalOffer')
11
 Condition= get_model('offer', 'Condition')
11
 Condition= get_model('offer', 'Condition')
12
+OrderDiscount = get_model('order', 'OrderDiscount')
12
 Benefit = get_model('offer', 'Benefit')
13
 Benefit = get_model('offer', 'Benefit')
13
 MetaDataForm, ConditionForm, BenefitForm, PreviewForm = get_classes('dashboard.offers.forms', [
14
 MetaDataForm, ConditionForm, BenefitForm, PreviewForm = get_classes('dashboard.offers.forms', [
14
     'MetaDataForm', 'ConditionForm', 'BenefitForm', 'PreviewForm'])
15
     'MetaDataForm', 'ConditionForm', 'BenefitForm', 'PreviewForm'])
53
             return True
54
             return True
54
         return self.previous_view.is_valid(self, request)
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
     def _store_form_kwargs(self, form):
65
     def _store_form_kwargs(self, form):
57
         session_data = self.request.session.setdefault(self.wizard_name, {})
66
         session_data = self.request.session.setdefault(self.wizard_name, {})
58
         form_kwargs = {'data': form.cleaned_data.copy()}
67
         form_kwargs = {'data': form.cleaned_data.copy()}
59
-        session_data[self.step_name] = form_kwargs
68
+        session_data[self._key()] = form_kwargs
60
         self.request.session.save()
69
         self.request.session.save()
61
 
70
 
62
     def _fetch_form_kwargs(self, step_name=None):
71
     def _fetch_form_kwargs(self, step_name=None):
63
         if not step_name:
72
         if not step_name:
64
             step_name = self.step_name
73
             step_name = self.step_name
65
         session_data = self.request.session.setdefault(self.wizard_name, {})
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
     def _store_object(self, form):
77
     def _store_object(self, form):
69
         session_data = self.request.session.setdefault(self.wizard_name, {})
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
         self.request.session.save()
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
         session_data = self.request.session.setdefault(self.wizard_name, {})
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
     def _flush_session(self):
86
     def _flush_session(self):
82
         self.request.session[self.wizard_name] = {}
87
         self.request.session[self.wizard_name] = {}
221
     def get_success_url(self):
226
     def get_success_url(self):
222
         messages.success(self.request, "Offer deleted!")
227
         messages.success(self.request, "Offer deleted!")
223
         return reverse('dashboard:offer-list')
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
 class ConditionalOfferAdmin(admin.ModelAdmin):
15
 class ConditionalOfferAdmin(admin.ModelAdmin):
16
     list_display = ('name', 'offer_type', 'start_date', 'end_date', 'condition', 'benefit', 'total_discount')
16
     list_display = ('name', 'offer_type', 'start_date', 'end_date', 'condition', 'benefit', 'total_discount')
17
     list_filter = ('offer_type',)
17
     list_filter = ('offer_type',)
18
-    readonly_fields = ('total_discount',)
18
+    readonly_fields = ('total_discount', 'num_orders')
19
     fieldsets = (
19
     fieldsets = (
20
         (None, {
20
         (None, {
21
             'fields': ('name', 'description', 'offer_type', 'condition', 'benefit', 'start_date', 'end_date', 'priority')
21
             'fields': ('name', 'description', 'offer_type', 'condition', 'benefit', 'start_date', 'end_date', 'priority')
22
         }),
22
         }),
23
         ('Usage', {
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
 
52
 
53
     # We track some information on usage
53
     # We track some information on usage
54
     total_discount = models.DecimalField(decimal_places=2, max_digits=12, default=Decimal('0.00'))
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
     date_created = models.DateTimeField(auto_now_add=True)
57
     date_created = models.DateTimeField(auto_now_add=True)
57
 
58
 
82
         return self._proxy_condition().is_satisfied(basket)
83
         return self._proxy_condition().is_satisfied(basket)
83
         
84
         
84
     def apply_benefit(self, basket):
85
     def apply_benefit(self, basket):
85
-        u"""
86
+        """
86
         Applies the benefit to the given basket and returns the discount.
87
         Applies the benefit to the given basket and returns the discount.
87
         """
88
         """
88
         if not self.is_condition_satisfied(basket):
89
         if not self.is_condition_satisfied(basket):
96
         return self._voucher        
97
         return self._voucher        
97
         
98
         
98
     def _proxy_condition(self):
99
     def _proxy_condition(self):
99
-        u"""
100
+        """
100
         Returns the appropriate proxy model for the condition
101
         Returns the appropriate proxy model for the condition
101
         """
102
         """
102
         field_dict = self.condition.__dict__
103
         field_dict = self.condition.__dict__
111
         return self.condition
112
         return self.condition
112
     
113
     
113
     def _proxy_benefit(self):
114
     def _proxy_benefit(self):
114
-        u"""
115
+        """
115
         Returns the appropriate proxy model for the condition
116
         Returns the appropriate proxy model for the condition
116
         """
117
         """
117
         field_dict = self.benefit.__dict__
118
         field_dict = self.benefit.__dict__
126
         elif self.benefit.type == self.benefit.FIXED_PRICE:
127
         elif self.benefit.type == self.benefit.FIXED_PRICE:
127
             return FixedPriceBenefit(**field_dict)
128
             return FixedPriceBenefit(**field_dict)
128
         return self.benefit
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
 class Condition(models.Model):
137
 class Condition(models.Model):

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

1
 from django.dispatch import receiver
1
 from django.dispatch import receiver
2
 from django.db.models.signals import m2m_changed, post_save
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
 from oscar.apps.basket.abstract_models import AbstractBasket
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
 @receiver(m2m_changed)
11
 @receiver(m2m_changed)
10
 def receive_basket_voucher_change(sender, **kwargs):
12
 def receive_basket_voucher_change(sender, **kwargs):
15
         voucher.num_basket_additions += 1
17
         voucher.num_basket_additions += 1
16
         voucher.save()
18
         voucher.save()
17
 
19
 
20
+
18
 @receiver(post_save, sender=OrderDiscount)        
21
 @receiver(post_save, sender=OrderDiscount)        
19
 def receive_order_discount_save(sender, instance, **kwargs):
22
 def receive_order_discount_save(sender, instance, **kwargs):
20
     # Record the amount of discount against the appropriate offers
23
     # Record the amount of discount against the appropriate offers
24
         discount.voucher.total_discount += discount.amount
27
         discount.voucher.total_discount += discount.amount
25
         discount.voucher.save()
28
         discount.voucher.save()
26
     if discount.offer:
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
 	</table>
41
 	</table>
42
 
42
 
43
 	<div class="form-actions">
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
 		<a href="{% url dashboard:offer-list %}">cancel</a>
45
 		<a href="{% url dashboard:offer-list %}">cancel</a>
46
 	</div>
46
 	</div>
47
 </form>
47
 </form>

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

4
 from django.test import TestCase
4
 from django.test import TestCase
5
 from django.test.client import Client
5
 from django.test.client import Client
6
 from django.contrib.auth.models import User
6
 from django.contrib.auth.models import User
7
+from purl import URL
7
 
8
 
8
 
9
 
9
 @contextmanager
10
 @contextmanager
31
         self.client = Client()
32
         self.client = Client()
32
         if not self.is_anonymous:
33
         if not self.is_anonymous:
33
             self.user = self.create_user()
34
             self.user = self.create_user()
34
-            self.client.login(username=self.username, 
35
+            self.client.login(username=self.username,
35
                               password=self.password)
36
                               password=self.password)
36
 
37
 
37
     def create_user(self):
38
     def create_user(self):
43
         user.save()
44
         user.save()
44
         return user
45
         return user
45
 
46
 
46
-    def assertIsRedirect(self, response):
47
+    def assertIsRedirect(self, response, expected_url=None):
47
         self.assertTrue(response.status_code in (httplib.FOUND,
48
         self.assertTrue(response.status_code in (httplib.FOUND,
48
                                                  httplib.MOVED_PERMANENTLY))
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
     def assertIsOk(self, response):
56
     def assertIsOk(self, response):
51
         self.assertEqual(httplib.OK, response.status_code)
57
         self.assertEqual(httplib.OK, response.status_code)

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

12
 twill==0.9
12
 twill==0.9
13
 PyHamcrest==1.6
13
 PyHamcrest==1.6
14
 South==0.7.3
14
 South==0.7.3
15
+purl==0.3.2

Loading…
取消
儲存