Browse Source

Merged in master - plus fixes to JS based on jshint

master
David Winterbottom 14 years ago
parent
commit
a4438c80e7

+ 2
- 2
oscar/apps/basket/views.py View File

@@ -50,7 +50,7 @@ class BasketView(ModelFormSetView):
50 50
     def formset_valid(self, formset):
51 51
         needs_auth = False
52 52
         for form in formset:
53
-            if form.cleaned_data['save_for_later']:
53
+            if hasattr(form, 'cleaned_data') and form.cleaned_data['save_for_later']:
54 54
                 line = form.instance
55 55
                 if self.request.user.is_authenticated():
56 56
                     self.move_line_to_saved_basket(line)
@@ -232,4 +232,4 @@ class SavedView(ModelFormSetView):
232 232
         return super(SavedView, self).formset_valid(formset)
233 233
 
234 234
     def formset_invalid(self, formset):
235
-        return HttpResponseRedirect(self.request.META.get('HTTP_REFERER', reverse('basket:summary')))
235
+        return HttpResponseRedirect(self.request.META.get('HTTP_REFERER', reverse('basket:summary')))

+ 4
- 1
oscar/apps/catalogue/abstract_models.py View File

@@ -94,7 +94,10 @@ class AbstractProductCategory(models.Model):
94 94
     class Meta:
95 95
         abstract = True
96 96
         ordering = ['-is_canonical']
97
-        verbose_name_plural = 'Categories'
97
+        verbose_name_plural = 'Product categories'
98
+
99
+    def __unicode__(self):
100
+        return u"<productcategory for product '%s'>" % self.product
98 101
         
99 102
 
100 103
 class AbstractContributorRole(models.Model):

+ 1
- 0
oscar/apps/catalogue/admin.py View File

@@ -54,3 +54,4 @@ admin.site.register(product_models.AttributeEntityType)
54 54
 admin.site.register(product_models.Option, OptionAdmin)
55 55
 admin.site.register(product_models.ProductImage)
56 56
 admin.site.register(product_models.Category)
57
+admin.site.register(product_models.ProductCategory)

+ 3
- 1
oscar/apps/checkout/views.py View File

@@ -236,6 +236,7 @@ class UserAddressDeleteView(CheckoutSessionMixin, DeleteView):
236 236
     """
237 237
     Delete an address from a user's addressbook.
238 238
     """
239
+    template_name = 'checkout/user_address_delete.html'
239 240
 
240 241
     def get_queryset(self):
241 242
         return UserAddress._default_manager.filter(user=self.request.user)
@@ -574,7 +575,8 @@ class OrderPlacementMixin(CheckoutSessionMixin):
574 575
 
575 576
     def send_confirmation_message(self, order, **kwargs):
576 577
         code = self.communication_type_code
577
-        ctx = {'order': order}
578
+        ctx = {'order': order,
579
+               'lines': order.lines.all(),}
578 580
         try:
579 581
             event_type = CommunicationEventType.objects.get(code=code)
580 582
         except CommunicationEventType.DoesNotExist:

+ 12
- 0
oscar/apps/dashboard/catalogue/forms.py View File

@@ -1,9 +1,11 @@
1 1
 from django import forms
2
+from django.forms.models import inlineformset_factory
2 3
 from django.db.models import get_model
3 4
 
4 5
 Product = get_model('catalogue', 'Product')
5 6
 StockRecord = get_model('partner', 'StockRecord')
6 7
 ProductAttributeValue = get_model('catalogue', 'ProductAttributeValue')
8
+ProductCategory = get_model('catalogue', 'ProductCategory')
7 9
 
8 10
 
9 11
 class ProductSearchForm(forms.Form):
@@ -121,3 +123,13 @@ class ProductForm(forms.ModelForm):
121 123
 
122 124
 class StockAlertSearchForm(forms.Form):
123 125
     status = forms.CharField(label='Status')
126
+
127
+
128
+class ProductCategoryForm(forms.ModelForm):
129
+    class Meta:
130
+        model = ProductCategory
131
+        exclude = ('product',)
132
+
133
+
134
+ProductCategoryFormSet = inlineformset_factory(Product, ProductCategory,
135
+                                               fields=('category',), extra=1)

+ 20
- 7
oscar/apps/dashboard/catalogue/views.py View File

@@ -6,10 +6,12 @@ from django.core.urlresolvers import reverse
6 6
 
7 7
 from oscar.apps.dashboard.catalogue import forms
8 8
 from oscar.core.loading import get_classes
9
-ProductForm, StockRecordForm, StockAlertSearchForm = get_classes(
9
+ProductForm, StockRecordForm, StockAlertSearchForm, ProductCategoryFormSet = get_classes(
10 10
     'dashboard.catalogue.forms', ('ProductForm', 'StockRecordForm',
11
-                                  'StockAlertSearchForm'))
11
+                                  'StockAlertSearchForm',
12
+                                  'ProductCategoryFormSet'))
12 13
 Product = get_model('catalogue', 'Product')
14
+ProductCategory = get_model('catalogue', 'ProductCategory')
13 15
 ProductClass = get_model('catalogue', 'ProductClass')
14 16
 StockRecord = get_model('partner', 'StockRecord')
15 17
 StockAlert = get_model('partner', 'StockAlert')
@@ -53,6 +55,7 @@ class ProductListView(generic.ListView):
53 55
 
54 56
         return queryset
55 57
 
58
+
56 59
 class ProductCreateRedirectView(generic.RedirectView):
57 60
 
58 61
     def get_redirect_url(self, **kwargs):
@@ -76,6 +79,7 @@ class ProductCreateView(generic.CreateView):
76 79
     def get_context_data(self, **kwargs):
77 80
         ctx = super(ProductCreateView, self).get_context_data(**kwargs)
78 81
         ctx['stockrecord_form'] = StockRecordForm()
82
+        ctx['category_formset'] = ProductCategoryFormSet()
79 83
         ctx['title'] = 'Create new product'
80 84
         return ctx
81 85
 
@@ -88,16 +92,20 @@ class ProductCreateView(generic.CreateView):
88 92
         return kwargs
89 93
 
90 94
     def form_valid(self, form):
95
+        product = form.save(commit=False)
96
+        product.product_class = self.get_product_class()
91 97
         stockrecord_form = StockRecordForm(self.request.POST)
92
-        if stockrecord_form.is_valid():
98
+        category_formset = ProductCategoryFormSet(self.request.POST,
99
+                                                  instance=product)
100
+        if stockrecord_form.is_valid() and category_formset.is_valid():
93 101
             # Save product
94
-            product = form.save()
95
-            product.product_class = self.get_product_class()
96 102
             product.save()
97 103
             # Save stock record
98 104
             stockrecord = stockrecord_form.save(commit=False)
99 105
             stockrecord.product = product
100 106
             stockrecord.save()
107
+            # Save categories
108
+            category_formset.save()
101 109
             return HttpResponseRedirect(self.get_success_url(product))
102 110
 
103 111
         ctx = self.get_context_data()
@@ -119,6 +127,7 @@ class ProductUpdateView(generic.UpdateView):
119 127
     def get_context_data(self, **kwargs):
120 128
         ctx = super(ProductUpdateView, self).get_context_data(**kwargs)
121 129
         ctx['stockrecord_form'] = StockRecordForm(instance=self.object.stockrecord)
130
+        ctx['category_formset'] = ProductCategoryFormSet(instance=self.object)
122 131
         ctx['title'] = 'Update product'
123 132
         return ctx
124 133
 
@@ -130,14 +139,18 @@ class ProductUpdateView(generic.UpdateView):
130 139
     def form_valid(self, form):
131 140
         stockrecord_form = StockRecordForm(self.request.POST,
132 141
                                            instance=self.object.stockrecord)
133
-        if stockrecord_form.is_valid():
134
-            form.save()
142
+        category_formset = ProductCategoryFormSet(self.request.POST,
143
+                                                  instance=self.object)
144
+        if stockrecord_form.is_valid() and category_formset.is_valid():
145
+            product = form.save()
135 146
             stockrecord_form.save()
147
+            category_formset.save()
136 148
             return HttpResponseRedirect(self.get_success_url())
137 149
 
138 150
         ctx = self.get_context_data()
139 151
         ctx['form'] = form
140 152
         ctx['stockrecord_form'] = stockrecord_form
153
+        ctx['category_formset'] = category_form
141 154
         return self.render_to_response(ctx)
142 155
 
143 156
     def get_success_url(self):

+ 29
- 7
oscar/apps/dashboard/promotions/views.py View File

@@ -6,16 +6,18 @@ from django.core.urlresolvers import reverse
6 6
 from django.contrib import messages
7 7
 from django.http import HttpResponseRedirect
8 8
 from django.db.models import Count
9
+from django.shortcuts import HttpResponse
9 10
 
10 11
 from oscar.core.loading import get_classes, get_class
11 12
 from oscar.apps.promotions.layout import split_by_position
12 13
 from oscar.apps.promotions.conf import PROMOTION_CLASSES, PROMOTION_POSITIONS
14
+from oscar.views.generic import PostActionMixin
13 15
 
14 16
 SingleProduct, RawHTML, Image, MultiImage, \
15 17
     AutomaticProductList, PagePromotion, HandPickedProductList = get_classes('promotions.models',
16 18
     ['SingleProduct', 'RawHTML', 'Image', 'MultiImage', 'AutomaticProductList',
17 19
      'PagePromotion', 'HandPickedProductList'])
18
-SelectForm, RawHTMLForm, PagePromotionForm = get_classes('dashboard.promotions.forms', 
20
+SelectForm, RawHTMLForm, PagePromotionForm = get_classes('dashboard.promotions.forms',
19 21
     ['PromotionTypeSelectForm', 'RawHTMLForm', 'PagePromotionForm'])
20 22
 
21 23
 
@@ -28,7 +30,7 @@ class ListView(generic.TemplateView):
28 30
         data = []
29 31
         for klass in PROMOTION_CLASSES:
30 32
             data.append(klass.objects.all())
31
-        promotions = itertools.chain(*data)                                    
33
+        promotions = itertools.chain(*data)
32 34
         ctx = {
33 35
             'promotions': promotions,
34 36
             'select_form': SelectForm(),
@@ -43,7 +45,7 @@ class CreateRedirectView(generic.RedirectView):
43 45
         code = self.request.GET.get('promotion_type', None)
44 46
         urls = {}
45 47
         for klass in PROMOTION_CLASSES:
46
-            urls[klass.classname()] = reverse('dashboard:promotion-create-%s' % 
48
+            urls[klass.classname()] = reverse('dashboard:promotion-create-%s' %
47 49
                                               klass.classname())
48 50
         return urls.get(code, None)
49 51
 
@@ -80,6 +82,26 @@ class PageDetailView(generic.TemplateView):
80 82
             })
81 83
         return ctx
82 84
 
85
+    def post(self, request, **kwargs):
86
+        """
87
+        When called with a post request, try and get 'promo[]' from
88
+        the post data and use it to reorder the page content blocks.
89
+        """
90
+        data = dict(request.POST).get('promo[]')
91
+        self._save_page_order(data)
92
+        return HttpResponse(status=200)
93
+
94
+    def _save_page_order(self, data):
95
+        """ 
96
+        Save the order of the pages. This gets used when an ajax request
97
+        posts backa new order for promotions within page regions.
98
+        """
99
+        for index, item in enumerate(data):
100
+            page = PagePromotion.objects.get(pk=item)
101
+            if page.display_order != index:
102
+                page.display_order = index
103
+                page.save()
104
+
83 105
 
84 106
 class PromotionMixin(object):
85 107
 
@@ -94,7 +116,7 @@ class DeletePagePromotionView(generic.DeleteView):
94 116
 
95 117
     def get_success_url(self):
96 118
         messages.info(self.request, "Promotion removed successfully")
97
-        return reverse('dashboard:promotion-list-by-url', 
119
+        return reverse('dashboard:promotion-list-by-url',
98 120
                        kwargs={'path': self.object.page_url})
99 121
 
100 122
 
@@ -107,7 +129,7 @@ class CreateView(PromotionMixin, generic.CreateView):
107 129
 
108 130
     def get_success_url(self):
109 131
         messages.info(self.request, "Promotion created successfully")
110
-        return reverse('dashboard:promotion-update', 
132
+        return reverse('dashboard:promotion-update',
111 133
                        kwargs={'ptype': self.model.classname(),
112 134
                                'pk': self.object.id})
113 135
 
@@ -146,7 +168,7 @@ class CreateHandPickedProductListView(CreateView):
146 168
 # ============
147 169
 # UPDATE VIEWS
148 170
 # ============
149
-        
171
+
150 172
 
151 173
 class UpdateView(PromotionMixin, generic.UpdateView):
152 174
     actions = ('add_to_page', 'remove_from_page')
@@ -225,7 +247,7 @@ class UpdateHandPickedProductListView(UpdateView):
225 247
 # ============
226 248
 # DELETE VIEWS
227 249
 # ============
228
-        
250
+
229 251
 
230 252
 class DeleteView(generic.DeleteView):
231 253
     template_name = 'dashboard/promotions/delete.html'

+ 2
- 1
oscar/apps/partner/tests/models.py View File

@@ -62,7 +62,8 @@ class DefaultWrapperTests(unittest.TestCase):
62 62
 
63 63
     def test_default_wrapper_for_out_of_stock(self):
64 64
         product = create_product(price=D('10.00'), partner="Acme", num_in_stock=0)
65
-        self.assertEquals("Out of stock", product.stockrecord.availability)
65
+        self.assertEquals(u"Not available",
66
+                          unicode(product.stockrecord.availability))
66 67
         self.assertEqual("outofstock", product.stockrecord.availability_code)
67 68
 
68 69
     def test_dispatch_date_for_in_stock(self):

+ 1
- 1
oscar/apps/partner/wrappers.py View File

@@ -31,7 +31,7 @@ class DefaultWrapper(object):
31 31
     def availability(self, stockrecord):
32 32
         if stockrecord.net_stock_level > 0:
33 33
             return _("In stock (%d available)" % stockrecord.net_stock_level)
34
-        return _("Not available ...")
34
+        return _("Not available")
35 35
     
36 36
     def dispatch_date(self, stockrecord):
37 37
         if stockrecord.net_stock_level:

+ 3
- 3
oscar/apps/payment/forms.py View File

@@ -188,7 +188,7 @@ class BankcardForm(forms.ModelForm):
188 188
     
189 189
     number = BankcardNumberField(max_length=20, widget=forms.TextInput(attrs={'autocomplete':'off'}), label="Card number")
190 190
     name = forms.CharField(max_length=128, label="Name on card")
191
-    ccv_number = forms.RegexField(required=True, label="CCV Number",
191
+    cvv_number = forms.RegexField(required=True, label="CVV Number",
192 192
                                   regex=r'^\d{3,4}$', widget=forms.TextInput(attrs={'size': '5'}))
193 193
     start_month = BankcardStartingMonthField(label="Valid from", required=False)
194 194
     expiry_month = BankcardExpiryMonthField(required=True, label = "Valid to")
@@ -196,7 +196,7 @@ class BankcardForm(forms.ModelForm):
196 196
     class Meta:
197 197
         model = payment_models.Bankcard
198 198
         exclude = ('user', 'partner_reference')
199
-        fields = ('number', 'name', 'start_month', 'expiry_month', 'ccv_number')
199
+        fields = ('number', 'name', 'start_month', 'expiry_month', 'cvv_number')
200 200
         
201 201
     def get_bankcard_obj(self):
202 202
         """
@@ -206,7 +206,7 @@ class BankcardForm(forms.ModelForm):
206 206
             'name': self.cleaned_data['name'],
207 207
             'card_number': self.cleaned_data['number'],
208 208
             'expiry_date': self.cleaned_data['expiry_month'].strftime("%m/%y"),
209
-            'ccv': self.cleaned_data['ccv_number'],
209
+            'cvv': self.cleaned_data['cvv_number'],
210 210
         }
211 211
         if self.cleaned_data['start_month']:
212 212
             kwargs['start_date'] = self.cleaned_data['start_month'].strftime("%m/%y")

+ 8
- 4
oscar/apps/payment/utils.py View File

@@ -1,11 +1,15 @@
1
-
2
-
3 1
 class Bankcard(object):
4 2
     
5
-    def __init__(self, card_number, expiry_date, name=None, ccv=None, start_date=None, issue_number=None):
3
+    def __init__(self, card_number, expiry_date, name=None, cvv=None, start_date=None, issue_number=None):
6 4
         self.card_number = card_number
7 5
         self.card_holder_name = name
8 6
         self.expiry_date = expiry_date
9 7
         self.start_date = start_date
10 8
         self.issue_number = issue_number
11
-        self.ccv = ccv
9
+        self.cvv = cvv
10
+
11
+    @property
12
+    def ccv(self):
13
+        # There are lots of acronyms for this -
14
+        # see http://en.wikipedia.org/wiki/Card_Code_Verification
15
+        return self.cvv

+ 31
- 9
oscar/static/js/oscar/dashboard.js View File

@@ -1,4 +1,14 @@
1
-var oscar = oscar || {}
1
+var oscar = oscar || {};
2
+oscar.get_csrf_token = function() {
3
+    var cookies = document.cookie.split(';');
4
+    $.each(cookies, function(index, cookie) {
5
+        cookie_parts = $.trim(cookie).split('=');
6
+        if (cookie_parts[0] == 'csrftoken') {
7
+            return cookie_parts[1];
8
+        }
9
+    });
10
+    return null;
11
+};
2 12
 oscar.dashboard = {
3 13
     promotions: {
4 14
         init: function() {
@@ -7,14 +17,26 @@ oscar.dashboard = {
7 17
                 stop: oscar.dashboard.promotions.save_order});
8 18
         },
9 19
         save_order: function(event, ui) {
10
-            // todo - save order of promotions
11
-            console.log(event, ui);
20
+            // Get the csrf token, otherwise django will not accept the
21
+            // POST request.
22
+            var serial = $(this).sortable("serialize"),
23
+                csrf = oscar.get_csrf_token();
24
+            serial = serial + '&csrfmiddlewaretoken=' + csrf;
25
+            $.ajax({
26
+                type: 'POST',
27
+                data: serial,
28
+                dataType: "json",
29
+                url: '#',
30
+                beforeSend: function(xhr, settings) {
31
+                    xhr.setRequestHeader("X-CSRFToken", csrf);
32
+                }
33
+            });
12 34
         }
13 35
     }
14
-}
36
+};
15 37
 
16
-$(document).ready(function() 
17
-{   
38
+$(document).ready(function()
39
+{
18 40
     //table font size increase decrease
19 41
     $('.fontsize li').click(function()
20 42
     {
@@ -23,12 +45,12 @@ $(document).ready(function()
23 45
         var num = parseFloat(os, 10);// gets rid of the px
24 46
         $('.bordered-table').css('font-size', num / 1.1 + uom);
25 47
         if (this.id == 'larger') {
26
-            $('.bordered-table').css('font-size', num * 1.1 + uom);    
27
-        }  
48
+            $('.bordered-table').css('font-size', num * 1.1 + uom);
49
+        }
28 50
     });
29 51
 
30 52
     //side navigation accordion
31
-    $('.primary-nav > li > ul, .orders_search').each(function(index) 
53
+    $('.primary-nav > li > ul, .orders_search').each(function(index)
32 54
     {
33 55
         $(this).css('height', $(this).height());
34 56
     });

+ 39
- 45
oscar/static/js/oscar/ui.js View File

@@ -1,5 +1,5 @@
1 1
 $(document).ready(function()
2
-{	
2
+{   
3 3
     // Product star rating  -- must improve this in python
4 4
     $('.product_pod, .span6, .promotion_single').each(function() 
5 5
     {
@@ -11,15 +11,15 @@ $(document).ready(function()
11 11
         });
12 12
         var ave_rating = sum_rating_count / sum_total_reviews *10;
13 13
         if (ave_rating <= 2) {
14
-            var ave_rating = 'One'
14
+            ave_rating = 'One';
15 15
         } else if (ave_rating <= 4) {
16
-            var ave_rating = 'Two'
16
+            ave_rating = 'Two';
17 17
         } else if (ave_rating <= 6) {
18
-            var ave_rating = 'Three'
18
+            ave_rating = 'Three';
19 19
         } else if (ave_rating <= 8) {
20
-            var ave_rating = 'Four'
20
+            ave_rating = 'Four';
21 21
         } else if (ave_rating <= 10) {
22
-            var ave_rating = 'Five'
22
+            ave_rating = 'Five';
23 23
         }
24 24
         $(this).find('.review_count')
25 25
           .after('<p class=\"star ' + ave_rating + '\">' + ave_rating + ' star(s) by user reviews. <a href=\"#reviews\">Add review</a></p>')
@@ -34,32 +34,26 @@ $(document).ready(function()
34 34
             user_rating += parseFloat($(this).text());
35 35
         });
36 36
         if (user_rating == 1) {
37
-            var user_rating = 'One'
37
+            user_rating = 'One';
38 38
         }
39 39
         else if (user_rating == 2) {
40
-            var user_rating = 'Two'
40
+            user_rating = 'Two';
41 41
         }
42 42
         else if (user_rating == 3) {
43
-            var user_rating = 'Three'
43
+            user_rating = 'Three';
44 44
         }
45 45
         else if (user_rating == 4) {
46
-            var user_rating = 'Four'
46
+            user_rating = 'Four';
47 47
         }
48 48
         else if (user_rating == 5) {
49
-            var user_rating = 'Five'
49
+            user_rating = 'Five';
50 50
         }
51
-        $(this)
52
-          .find('h3')
53
-          .addClass(user_rating)
54
-          .end()
55
-          .find('span')
56
-          .remove();
51
+        $(this).find('h3').addClass(user_rating).end().find('span').remove();
57 52
     });
58 53
     
59
-    
60
-    var window_width = $(window).width(); // Width of the window
61
-        $browse_width = $('aside.span3').outerWidth(),// Width of main navigation
62
-        $browse_height = $('#browse > .dropdown-menu').outerHeight();// Height of main navigation
54
+    var window_width = $(window).width(), // Width of the window
55
+        $browse_width = $('aside.span3').outerWidth(), // Width of main navigation
56
+        $browse_height = $('#browse > .dropdown-menu').outerHeight(); // Height of main navigation
63 57
     
64 58
     if (window_width > 480) {
65 59
       // This activates elastislide
@@ -124,29 +118,29 @@ $(document).ready(function()
124 118
     $(".accordion dd").hide();
125 119
 
126 120
     /* scroll to sections */
127
-  	$('.top_page a, .product_page a').click(function (e) {
128
-  		var section = $(this).attr('href');
129
-  		var sectionPosition = Math.floor($(section).offset().top);
130
-  		var currentPosition = Math.floor($(document).scrollTop());
131
-  		// when scrolling downwards
132
-  		if (sectionPosition > currentPosition) {
133
-  			$('html, body').animate({
134
-  				scrollTop: sectionPosition}, 500, function() {
135
-  				$('html, body').animate({
136
-  					scrollTop: sectionPosition
137
-  				});
138
-  			});
139
-  		}
140
-  		// when scrolling upwards
141
-  		else if (sectionPosition < currentPosition) {
142
-  			$('html, body').animate({
143
-  				scrollTop: sectionPosition}, 500, function() {
144
-  				$('html, body').animate({
145
-  					scrollTop: sectionPosition
146
-  				});
147
-  			});			
148
-  		}
149
-  		e.preventDefault();
150
-  	});
121
+    $('.top_page a, .product_page a').click(function (e) {
122
+        var section = $(this).attr('href');
123
+        var sectionPosition = Math.floor($(section).offset().top);
124
+        var currentPosition = Math.floor($(document).scrollTop());
125
+        // when scrolling downwards
126
+        if (sectionPosition > currentPosition) {
127
+            $('html, body').animate({
128
+                scrollTop: sectionPosition}, 500, function() {
129
+                $('html, body').animate({
130
+                    scrollTop: sectionPosition
131
+                });
132
+            });
133
+        }
134
+        // when scrolling upwards
135
+        else if (sectionPosition < currentPosition) {
136
+            $('html, body').animate({
137
+                scrollTop: sectionPosition}, 500, function() {
138
+                $('html, body').animate({
139
+                    scrollTop: sectionPosition
140
+                });
141
+            });         
142
+        }
143
+        e.preventDefault();
144
+    });
151 145
 });
152 146
     

+ 12
- 0
oscar/templates/checkout/user_address_delete.html View File

@@ -0,0 +1,12 @@
1
+{% extends "checkout/checkout.html" %}
2
+
3
+{% block shipping_address %}
4
+
5
+<h4>Delete address?</h4>
6
+<form action="." method="post">
7
+    {% csrf_token %}
8
+	{{ object.summary }}
9
+    <p>Are you sure you want to delete this address? <input type="submit" value="Yes!" /></p>
10
+</form>
11
+
12
+{% endblock shipping_address %}

+ 5
- 0
oscar/templates/dashboard/catalogue/product_update.html View File

@@ -25,6 +25,11 @@ Update product | {{ block.super }}
25 25
 	{% csrf_token %}
26 26
 		<legend>Product information</legend>
27 27
 		{% include "partials/form_fields.html" with form=form %}
28
+		<legend>Category information</legend>
29
+		{{ category_formset.management_form }}
30
+		{% for category_form in category_formset %}
31
+			{% include "partials/form_fields.html" with form=category_form %}
32
+		{% endfor %}
28 33
 		<legend>Stock and price information</legend>
29 34
 		{% include "partials/form_fields.html" with form=stockrecord_form %}
30 35
 		<div class="form-actions">

+ 2
- 3
oscar/templates/dashboard/layout.html View File

@@ -4,16 +4,14 @@
4 4
 {% load category_tags %}
5 5
 {% load dashboard_tags %}
6 6
 
7
-
8 7
 {% block extrahead %}
9 8
     <link rel="stylesheet" href="{{ STATIC_URL }}css/dashboard.css" />
10 9
 {%endblock extrahead %}
10
+
11 11
 {% block title %}
12 12
 Dashboard | {{ block.super }}
13 13
 {% endblock %}
14 14
 
15
-
16
-
17 15
 {% block layout %}
18 16
     <div class="navbar accounts">
19 17
         <div class="navbar-inner">
@@ -87,4 +85,5 @@ Dashboard | {{ block.super }}
87 85
 {% block extrascripts %}
88 86
     <!-- dashboard js -->
89 87
     <script src="{{ STATIC_URL }}js/oscar/dashboard.js" type="text/javascript" charset="utf-8"></script>
88
+    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js"></script>
90 89
 {% endblock %}

+ 1
- 1
oscar/templates/dashboard/promotions/page_detail.html View File

@@ -49,7 +49,7 @@ Content blocks for page {{ page }} | {{ block.super }}
49 49
 </table>
50 50
 <!-- <ul class="promotion_list">
51 51
     {% for promotion in position.promotions %}
52
-    <li>
52
+    <li id="promo_{{ promotion.pk }}">
53 53
     {{ promotion.content_object.name }} - Type: {{ promotion.content_object.type }}
54 54
     <a href="{% url dashboard:promotion-update promotion.content_object.code promotion.content_object.id %}" class="btn btn-success">Edit</a>
55 55
     <a href="#" class="btn btn-info btn-handle">Re-order</a>

+ 13
- 9
oscar/templates/partials/form_fields.html View File

@@ -1,13 +1,17 @@
1 1
 {% for field in form %}
2 2
 <div class="control-group {% for error in field.errors %}error{% endfor %}">
3
-    {{ field.label_tag }}
4
-    <div class="controls">
5
-        {{ field }}
6
-        {% for error in field.errors %}
7
-            <span class="help-block">
8
-                {{ error|escape }}
9
-            </span>
10
-        {% endfor %}
11
-    </div>
3
+	{% if field.is_hidden %}
4
+		{{ field }}
5
+	{% else %}
6
+		{{ field.label_tag }}
7
+		<div class="controls">
8
+			{{ field }}
9
+			{% for error in field.errors %}
10
+				<span class="help-block">
11
+					{{ error|escape }}
12
+				</span>
13
+			{% endfor %}
14
+		</div>
15
+	{% endif %}
12 16
 </div>
13 17
 {% endfor %}

+ 12
- 1
pre-commit.sh View File

@@ -1,7 +1,18 @@
1 1
 #!/usr/bin/env bash
2 2
 
3
+git stash --keep-index -q
4
+
3 5
 source ~/.virtualenvs/oscar/bin/activate
6
+
4 7
 ./run_tests.py
5
-[ $? -ne 0 ] && echo "Tests failed" && exit 1
8
+TEST_RESULT=$?
9
+
10
+jshint oscar/static/js/oscar
11
+JS_RESULT=$?
12
+
13
+git stash pop -q
14
+
15
+[ $TEST_RESULT -ne 0 ] && echo "Tests failed" && exit 1
16
+[ $JS_RESULT -ne 0 ] && echo "JShint failed" && exit 1
6 17
 
7 18
 exit 0

Loading…
Cancel
Save