Quellcode durchsuchen

Fix all flake8 issues.

master
Markus Bertheau vor 12 Jahren
Ursprung
Commit
c53d6cc0ae
100 geänderte Dateien mit 927 neuen und 666 gelöschten Zeilen
  1. 1
    1
      lint.sh
  2. 9
    6
      oscar/app.py
  3. 13
    14
      oscar/apps/address/abstract_models.py
  4. 1
    1
      oscar/apps/analytics/models.py
  5. 21
    21
      oscar/apps/basket/abstract_models.py
  6. 3
    3
      oscar/apps/basket/app.py
  7. 6
    6
      oscar/apps/basket/forms.py
  8. 4
    3
      oscar/apps/basket/reports.py
  9. 1
    1
      oscar/apps/basket/signals.py
  10. 7
    5
      oscar/apps/basket/views.py
  11. 5
    5
      oscar/apps/catalogue/abstract_models.py
  12. 6
    4
      oscar/apps/catalogue/app.py
  13. 7
    9
      oscar/apps/catalogue/managers.py
  14. 2
    2
      oscar/apps/catalogue/models.py
  15. 3
    1
      oscar/apps/catalogue/reviews/abstract_models.py
  16. 2
    1
      oscar/apps/catalogue/reviews/admin.py
  17. 3
    3
      oscar/apps/catalogue/reviews/app.py
  18. 8
    5
      oscar/apps/catalogue/reviews/managers.py
  19. 2
    1
      oscar/apps/catalogue/reviews/models.py
  20. 2
    1
      oscar/apps/catalogue/reviews/views.py
  21. 20
    9
      oscar/apps/catalogue/utils.py
  22. 6
    4
      oscar/apps/catalogue/views.py
  23. 3
    3
      oscar/apps/checkout/app.py
  24. 4
    1
      oscar/apps/checkout/context_processors.py
  25. 7
    6
      oscar/apps/checkout/decorators.py
  26. 2
    1
      oscar/apps/checkout/mixins.py
  27. 4
    3
      oscar/apps/checkout/utils.py
  28. 57
    31
      oscar/apps/checkout/views.py
  29. 15
    11
      oscar/apps/customer/abstract_models.py
  30. 10
    5
      oscar/apps/customer/alerts/utils.py
  31. 21
    11
      oscar/apps/customer/alerts/views.py
  32. 13
    9
      oscar/apps/customer/app.py
  33. 4
    3
      oscar/apps/customer/auth_backends.py
  34. 4
    2
      oscar/apps/customer/forms.py
  35. 0
    3
      oscar/apps/customer/mixins.py
  36. 2
    2
      oscar/apps/customer/models.py
  37. 4
    4
      oscar/apps/customer/notifications/views.py
  38. 7
    4
      oscar/apps/customer/utils.py
  39. 7
    5
      oscar/apps/customer/views.py
  40. 11
    7
      oscar/apps/customer/wishlists/views.py
  41. 3
    3
      oscar/apps/dashboard/app.py
  42. 11
    8
      oscar/apps/dashboard/catalogue/app.py
  43. 12
    6
      oscar/apps/dashboard/catalogue/forms.py
  44. 22
    17
      oscar/apps/dashboard/catalogue/views.py
  45. 3
    3
      oscar/apps/dashboard/communications/app.py
  46. 2
    2
      oscar/apps/dashboard/communications/views.py
  47. 0
    1
      oscar/apps/dashboard/models.py
  48. 5
    4
      oscar/apps/dashboard/nav.py
  49. 3
    3
      oscar/apps/dashboard/offers/app.py
  50. 9
    8
      oscar/apps/dashboard/offers/views.py
  51. 12
    10
      oscar/apps/dashboard/orders/app.py
  52. 21
    15
      oscar/apps/dashboard/orders/forms.py
  53. 98
    61
      oscar/apps/dashboard/orders/views.py
  54. 3
    3
      oscar/apps/dashboard/pages/app.py
  55. 2
    1
      oscar/apps/dashboard/pages/views.py
  56. 3
    3
      oscar/apps/dashboard/partners/app.py
  57. 2
    1
      oscar/apps/dashboard/partners/forms.py
  58. 10
    7
      oscar/apps/dashboard/partners/views.py
  59. 11
    11
      oscar/apps/dashboard/promotions/app.py
  60. 5
    9
      oscar/apps/dashboard/promotions/forms.py
  61. 29
    21
      oscar/apps/dashboard/promotions/views.py
  62. 4
    3
      oscar/apps/dashboard/ranges/forms.py
  63. 22
    10
      oscar/apps/dashboard/ranges/models.py
  64. 3
    3
      oscar/apps/dashboard/reports/app.py
  65. 15
    7
      oscar/apps/dashboard/reports/forms.py
  66. 0
    2
      oscar/apps/dashboard/reports/models.py
  67. 9
    7
      oscar/apps/dashboard/reports/reports.py
  68. 6
    5
      oscar/apps/dashboard/reports/utils.py
  69. 5
    4
      oscar/apps/dashboard/reports/views.py
  70. 5
    7
      oscar/apps/dashboard/reviews/app.py
  71. 1
    1
      oscar/apps/dashboard/reviews/forms.py
  72. 9
    8
      oscar/apps/dashboard/reviews/utils.py
  73. 17
    10
      oscar/apps/dashboard/reviews/views.py
  74. 3
    3
      oscar/apps/dashboard/users/app.py
  75. 17
    11
      oscar/apps/dashboard/users/views.py
  76. 8
    5
      oscar/apps/dashboard/views.py
  77. 3
    3
      oscar/apps/dashboard/vouchers/app.py
  78. 6
    3
      oscar/apps/dashboard/vouchers/forms.py
  79. 10
    5
      oscar/apps/dashboard/vouchers/views.py
  80. 2
    1
      oscar/apps/offer/admin.py
  81. 5
    4
      oscar/apps/offer/app.py
  82. 55
    48
      oscar/apps/offer/models.py
  83. 3
    2
      oscar/apps/offer/receivers.py
  84. 9
    5
      oscar/apps/offer/reports.py
  85. 31
    23
      oscar/apps/order/abstract_models.py
  86. 4
    6
      oscar/apps/order/models.py
  87. 4
    4
      oscar/apps/order/processing.py
  88. 4
    2
      oscar/apps/order/reports.py
  89. 1
    1
      oscar/apps/order/signals.py
  90. 16
    9
      oscar/apps/order/utils.py
  91. 4
    3
      oscar/apps/partner/abstract_models.py
  92. 3
    2
      oscar/apps/partner/admin.py
  93. 1
    1
      oscar/apps/partner/models.py
  94. 2
    1
      oscar/apps/partner/receivers.py
  95. 4
    3
      oscar/apps/partner/strategy.py
  96. 36
    19
      oscar/apps/partner/utils.py
  97. 6
    3
      oscar/apps/partner/wrappers.py
  98. 9
    10
      oscar/apps/payment/exceptions.py
  99. 12
    8
      oscar/apps/promotions/admin.py
  100. 0
    0
      oscar/apps/promotions/app.py

+ 1
- 1
lint.sh Datei anzeigen

@@ -6,7 +6,7 @@
6 6
 
7 7
 # Ideally, this figure should be < 100.  I'll keep reducing it as the 
8 8
 # codebase gets tidied up incrementally.
9
-THRESHOLD=795
9
+THRESHOLD=0
10 10
 
11 11
 # Some warnings aren't worth worrying about...
12 12
 IGNORE="W292,E202,E128,E124"

+ 9
- 6
oscar/app.py Datei anzeigen

@@ -23,12 +23,13 @@ class Shop(Application):
23 23
     def get_urls(self):
24 24
         # After we drop support for Django<1.6 the following line won't be
25 25
         # necessary, and the parameter uidb36 should be replaced with uidb64.
26
-        # The necessary update should also be done in oscar/apps/customer/utils.py
26
+        # The necessary update should also be done in
27
+        # oscar/apps/customer/utils.py
27 28
         password_reset_confirm = getattr(
28 29
             auth_views, 'password_reset_confirm_uidb36',
29 30
             auth_views.password_reset_confirm)
30 31
 
31
-        urlpatterns = patterns('',
32
+        urls = [
32 33
             (r'^i18n/', include('django.conf.urls.i18n')),
33 34
             (r'^catalogue/', include(self.catalogue_app.urls)),
34 35
             (r'^basket/', include(self.basket_app.urls)),
@@ -49,16 +50,18 @@ class Shop(Application):
49 50
             url(r'^password-reset/done/$',
50 51
                 login_forbidden(auth_views.password_reset_done),
51 52
                 name='password-reset-done'),
52
-            url(r'^password-reset/confirm/(?P<uidb36>[0-9A-Za-z]{1,13})-(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
53
+            url(r'^password-reset/confirm/(?P<uidb36>[0-9A-Za-z]{1,13})-'
54
+                r'(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
53 55
                 login_forbidden(password_reset_confirm),
54
-                {'post_reset_redirect': reverse_lazy('password-reset-complete')},
56
+                {'post_reset_redirect':
57
+                 reverse_lazy('password-reset-complete')},
55 58
                 name='password-reset-confirm'),
56 59
             url(r'^password-reset/complete/$',
57 60
                 login_forbidden(auth_views.password_reset_complete),
58 61
                 name='password-reset-complete'),
59 62
             (r'', include(self.promotions_app.urls)),
60
-        )
61
-        return urlpatterns
63
+        ]
64
+        return patterns('', *urls)
62 65
 
63 66
 
64 67
 # 'shop' kept for legacy projects - 'application' is a better name

+ 13
- 14
oscar/apps/address/abstract_models.py Datei anzeigen

@@ -268,8 +268,8 @@ class AbstractAddress(models.Model):
268 268
             country_code = self.country.iso_3166_1_a2
269 269
             regex = self.POSTCODES_REGEX.get(country_code, None)
270 270
             if regex:
271
-                msg = _("Addresses in %(country)s require a valid postcode") % {
272
-                        'country': self.country}
271
+                msg = _("Addresses in %(country)s require a valid postcode") \
272
+                    % {'country': self.country}
273 273
                 raise exceptions.ValidationError(msg)
274 274
 
275 275
         if self.postcode and self.country_id:
@@ -281,9 +281,9 @@ class AbstractAddress(models.Model):
281 281
             # Validate postcode against regext for the country if available
282 282
             if regex and not re.match(regex, postcode):
283 283
                 msg = _("The postcode '%(postcode)s' is not valid "
284
-                        "for %(country)s") % {
285
-                            'postcode': self.postcode,
286
-                            'country': self.country}
284
+                        "for %(country)s") \
285
+                    % {'postcode': self.postcode,
286
+                       'country': self.country}
287 287
                 raise exceptions.ValidationError(
288 288
                     {'postcode': msg})
289 289
 
@@ -497,15 +497,13 @@ class AbstractUserAddress(AbstractShippingAddress):
497 497
 
498 498
     def _ensure_defaults_integrity(self):
499 499
         if self.is_default_for_shipping:
500
-            self.__class__._default_manager.filter(
501
-                user=self.user,
502
-                is_default_for_shipping=True).update(
503
-                    is_default_for_shipping=False)
500
+            self.__class__._default_manager\
501
+                .filter(user=self.user, is_default_for_shipping=True)\
502
+                .update(is_default_for_shipping=False)
504 503
         if self.is_default_for_billing:
505
-            self.__class__._default_manager.filter(
506
-                user=self.user,
507
-                is_default_for_billing=True).update(
508
-                    is_default_for_billing=False)
504
+            self.__class__._default_manager\
505
+                .filter(user=self.user, is_default_for_billing=True)\
506
+                .update(is_default_for_billing=False)
509 507
 
510 508
     class Meta:
511 509
         abstract = True
@@ -523,7 +521,8 @@ class AbstractUserAddress(AbstractShippingAddress):
523 521
             qs = qs.exclude(id=self.id)
524 522
         if qs.exists():
525 523
             raise exceptions.ValidationError({
526
-                '__all__': [_("This address is already in your address book")]})
524
+                '__all__': [_("This address is already in your address"
525
+                              " book")]})
527 526
 
528 527
 
529 528
 class AbstractBillingAddress(AbstractAddress):

+ 1
- 1
oscar/apps/analytics/models.py Datei anzeigen

@@ -20,4 +20,4 @@ class UserSearch(AbstractUserSearch):
20 20
 
21 21
 
22 22
 # Import receiver functions
23
-from oscar.apps.analytics.receivers import *
23
+from oscar.apps.analytics.receivers import *  # noqa

+ 21
- 21
oscar/apps/basket/abstract_models.py Datei anzeigen

@@ -75,10 +75,10 @@ class AbstractBasket(models.Model):
75 75
 
76 76
     def __unicode__(self):
77 77
         return _(
78
-            u"%(status)s basket (owner: %(owner)s, lines: %(num_lines)d)") % {
79
-                'status': self.status,
80
-                'owner': self.owner,
81
-                'num_lines': self.num_lines}
78
+            u"%(status)s basket (owner: %(owner)s, lines: %(num_lines)d)") \
79
+            % {'status': self.status,
80
+               'owner': self.owner,
81
+               'num_lines': self.num_lines}
82 82
 
83 83
     # ========
84 84
     # Strategy
@@ -142,9 +142,8 @@ class AbstractBasket(models.Model):
142 142
             if qty > max_allowed:
143 143
                 return False, _(
144 144
                     "Due to technical limitations we are not able "
145
-                    "to ship more than %(threshold)d items in one order.") % {
146
-                        'threshold': basket_threshold,
147
-                    }
145
+                    "to ship more than %(threshold)d items in one order.") \
146
+                    % {'threshold': basket_threshold}
148 147
         return True, None
149 148
 
150 149
     # ============
@@ -182,8 +181,8 @@ class AbstractBasket(models.Model):
182 181
         if price_currency and stock_info.price.currency != price_currency:
183 182
             raise ValueError((
184 183
                 "Basket lines must all have the same currency. Proposed "
185
-                "line has currency %s, while basket has currency %s") % (
186
-                    stock_info.price.currency, price_currency))
184
+                "line has currency %s, while basket has currency %s")
185
+                % (stock_info.price.currency, price_currency))
187 186
 
188 187
         if stock_info.stockrecord is None:
189 188
             raise ValueError((
@@ -594,10 +593,10 @@ class AbstractLine(models.Model):
594 593
 
595 594
     def __unicode__(self):
596 595
         return _(
597
-            u"Basket #%(basket_id)d, Product #%(product_id)d, quantity %(quantity)d") % {
598
-                'basket_id': self.basket.pk,
599
-                'product_id': self.product.pk,
600
-                'quantity': self.quantity}
596
+            u"Basket #%(basket_id)d, Product #%(product_id)d, quantity"
597
+            u" %(quantity)d") % {'basket_id': self.basket.pk,
598
+                                 'product_id': self.product.pk,
599
+                                 'quantity': self.quantity}
601 600
 
602 601
     def save(self, *args, **kwargs):
603 602
         """
@@ -762,7 +761,8 @@ class AbstractLine(models.Model):
762 761
             # against tax inclusive prices but we need to guess how much of the
763 762
             # discount applies to tax-exclusive prices.  We do this by
764 763
             # assuming a linear tax and scaling down the original discount.
765
-            return self.line_price_excl_tax - self._tax_ratio * self._discount_incl_tax
764
+            return self.line_price_excl_tax \
765
+                - self._tax_ratio * self._discount_incl_tax
766 766
         return self.line_price_excl_tax
767 767
 
768 768
     @property
@@ -814,15 +814,15 @@ class AbstractLine(models.Model):
814 814
                 'new_price': currency(current_price_incl_tax)
815 815
             }
816 816
             if current_price_incl_tax > self.price_incl_tax:
817
-                warning = _("The price of '%(product)s' has increased from "
818
-                            "%(old_price)s to %(new_price)s since you added it "
819
-                            "to your basket")
817
+                warning = _("The price of '%(product)s' has increased from"
818
+                            " %(old_price)s to %(new_price)s since you added"
819
+                            " it to your basket")
820 820
                 return warning % product_prices
821 821
             else:
822
-                warning = _("The price of '%(product)s' has decreased from "
823
-                            "%(old_price)s to %(new_price)s since you added it "
824
-                            "to your basket")
825
-                return warning %  product_prices
822
+                warning = _("The price of '%(product)s' has decreased from"
823
+                            " %(old_price)s to %(new_price)s since you added"
824
+                            " it to your basket")
825
+                return warning % product_prices
826 826
 
827 827
 
828 828
 class AbstractLineAttribute(models.Model):

+ 3
- 3
oscar/apps/basket/app.py Datei anzeigen

@@ -14,7 +14,7 @@ class BasketApplication(Application):
14 14
     remove_voucher_view = views.VoucherRemoveView
15 15
 
16 16
     def get_urls(self):
17
-        urlpatterns = patterns('',
17
+        urls = [
18 18
             url(r'^$', self.summary_view.as_view(), name='summary'),
19 19
             url(r'^add/$', self.add_view.as_view(), name='add'),
20 20
             url(r'^vouchers/add/$', self.add_voucher_view.as_view(),
@@ -23,8 +23,8 @@ class BasketApplication(Application):
23 23
                 self.remove_voucher_view.as_view(), name='vouchers-remove'),
24 24
             url(r'^saved/$', login_required(self.saved_view.as_view()),
25 25
                 name='saved'),
26
-        )
27
-        return self.post_process_urls(urlpatterns)
26
+        ]
27
+        return self.post_process_urls(patterns('', *urls))
28 28
 
29 29
 
30 30
 application = BasketApplication()

+ 6
- 6
oscar/apps/basket/forms.py Datei anzeigen

@@ -31,8 +31,9 @@ class BasketLineForm(forms.ModelForm):
31 31
             raise forms.ValidationError(reason)
32 32
 
33 33
     def check_permission(self, qty):
34
-        is_available, reason = self.instance.stockinfo.availability.is_purchase_permitted(
35
-            quantity=qty)
34
+        is_available, reason \
35
+            = self.instance.stockinfo.availability.is_purchase_permitted(
36
+                quantity=qty)
36 37
         if not is_available:
37 38
             raise forms.ValidationError(reason)
38 39
 
@@ -191,10 +192,9 @@ class AddToBasketForm(forms.Form):
191 192
                 raise forms.ValidationError(
192 193
                     _("Due to technical limitations we are not able to ship"
193 194
                       " more than %(threshold)d items in one order. Your"
194
-                      " basket currently has %(basket)d items.") % {
195
-                          'threshold': basket_threshold,
196
-                          'basket': total_basket_quantity,
197
-                      })
195
+                      " basket currently has %(basket)d items.")
196
+                    % {'threshold': basket_threshold,
197
+                       'basket': total_basket_quantity})
198 198
         return qty
199 199
 
200 200
     def _create_group_product_fields(self, item):

+ 4
- 3
oscar/apps/basket/reports.py Datei anzeigen

@@ -23,7 +23,7 @@ class OpenBasketReportCSVFormatter(ReportCSVFormatter):
23 23
                       _('Num items'),
24 24
                       _('Date of creation'),
25 25
                       _('Time since creation'),
26
-                     ]
26
+                      ]
27 27
         writer.writerow(header_row)
28 28
 
29 29
         for basket in baskets:
@@ -80,7 +80,7 @@ class SubmittedBasketReportCSVFormatter(ReportCSVFormatter):
80 80
                       _('Num items'),
81 81
                       _('Date created'),
82 82
                       _('Time between creation and submission'),
83
-                     ]
83
+                      ]
84 84
         writer.writerow(header_row)
85 85
 
86 86
         for basket in baskets:
@@ -99,7 +99,8 @@ class SubmittedBasketReportCSVFormatter(ReportCSVFormatter):
99 99
 
100 100
 
101 101
 class SubmittedBasketReportHTMLFormatter(ReportHTMLFormatter):
102
-    filename_template = 'dashboard/reports/partials/submitted_basket_report.html'
102
+    filename_template = 'dashboard/reports/partials/' \
103
+        'submitted_basket_report.html'
103 104
 
104 105
 
105 106
 class SubmittedBasketReportGenerator(ReportGenerator):

+ 1
- 1
oscar/apps/basket/signals.py Datei anzeigen

@@ -1,4 +1,4 @@
1 1
 import django.dispatch
2 2
 
3 3
 basket_addition = django.dispatch.Signal(providing_args=["product", "user"])
4
-voucher_addition = django.dispatch.Signal(providing_args=["basket", "voucher"])
4
+voucher_addition = django.dispatch.Signal(providing_args=["basket", "voucher"])

+ 7
- 5
oscar/apps/basket/views.py Datei anzeigen

@@ -17,10 +17,11 @@ from oscar.apps.basket.signals import basket_addition, voucher_addition
17 17
 from oscar.core.loading import get_class, get_classes
18 18
 Applicator = get_class('offer.utils', 'Applicator')
19 19
 (BasketLineFormSet, BasketLineForm, AddToBasketForm, BasketVoucherForm,
20
- SavedLineFormSet, SavedLineForm, ProductSelectionForm) = get_classes(
21
-     'basket.forms', ('BasketLineFormSet', 'BasketLineForm', 'AddToBasketForm',
22
-                      'BasketVoucherForm', 'SavedLineFormSet',
23
-                      'SavedLineForm', 'ProductSelectionForm'))
20
+ SavedLineFormSet, SavedLineForm, ProductSelectionForm) \
21
+    = get_classes('basket.forms', ('BasketLineFormSet', 'BasketLineForm',
22
+                                   'AddToBasketForm', 'BasketVoucherForm',
23
+                                   'SavedLineFormSet', 'SavedLineForm',
24
+                                   'ProductSelectionForm'))
24 25
 Repository = get_class('shipping.repository', ('Repository'))
25 26
 OrderTotalCalculator = get_class(
26 27
     'checkout.calculators', 'OrderTotalCalculator')
@@ -124,7 +125,8 @@ class BasketView(ModelFormSetView):
124 125
         applied_offers = basket.offer_applications.offers.values()
125 126
         msgs = []
126 127
         for offer in offers:
127
-            if offer.is_condition_partially_satisfied(basket) and offer not in applied_offers:
128
+            if offer.is_condition_partially_satisfied(basket) \
129
+                    and offer not in applied_offers:
128 130
                 data = {
129 131
                     'message': offer.get_upsell_message(basket),
130 132
                     'offer': offer}

+ 5
- 5
oscar/apps/catalogue/abstract_models.py Datei anzeigen

@@ -133,7 +133,7 @@ class AbstractCategory(MP_Node):
133 133
         Moves the current node and all its descendants to a new position
134 134
         relative to another node.
135 135
 
136
-        See https://tabo.pe/projects/django-treebeard/docs/1.61/api.html#treebeard.models.Node.move
136
+        See https://tabo.pe/projects/django-treebeard/docs/1.61/api.html#treebeard.models.Node.move  # noqa
137 137
         """
138 138
         super(AbstractCategory, self).move(target, pos)
139 139
 
@@ -1066,9 +1066,10 @@ class AbstractProductImage(models.Model):
1066 1066
         _("Caption"), max_length=200, blank=True, null=True)
1067 1067
 
1068 1068
     #: Use display_order to determine which is the "primary" image
1069
-    display_order = models.PositiveIntegerField(_("Display Order"), default=0,
1070
-        help_text=_("""An image with a display order of
1071
-                       zero will be the primary image for a product"""))
1069
+    display_order = models.PositiveIntegerField(
1070
+        _("Display Order"), default=0,
1071
+        help_text=_("An image with a display order of zero will be the primary"
1072
+                    " image for a product"))
1072 1073
     date_created = models.DateTimeField(_("Date Created"), auto_now_add=True)
1073 1074
 
1074 1075
     class Meta:
@@ -1086,4 +1087,3 @@ class AbstractProductImage(models.Model):
1086 1087
         Return bool if image display order is 0
1087 1088
         """
1088 1089
         return self.display_order == 0
1089
-

+ 6
- 4
oscar/apps/catalogue/app.py Datei anzeigen

@@ -15,7 +15,7 @@ class BaseCatalogueApplication(Application):
15 15
 
16 16
     def get_urls(self):
17 17
         urlpatterns = super(BaseCatalogueApplication, self).get_urls()
18
-        urlpatterns += patterns('',
18
+        urls = [
19 19
             url(r'^$', self.index_view.as_view(), name='index'),
20 20
             url(r'^(?P<product_slug>[\w-]*)_(?P<pk>\d+)/$',
21 21
                 self.detail_view.as_view(), name='detail'),
@@ -25,7 +25,8 @@ class BaseCatalogueApplication(Application):
25 25
                 self.range_view.as_view(), name='range'),
26 26
             # Legacy route for the category view
27 27
             url(r'^(?P<category_slug>[\w-]+(/[\w-]+)*)/$',
28
-                self.category_view.as_view(), name='category'))
28
+                self.category_view.as_view(), name='category')]
29
+        urlpatterns += patterns('', *urls)
29 30
         return self.post_process_urls(urlpatterns)
30 31
 
31 32
 
@@ -35,10 +36,11 @@ class ReviewsApplication(Application):
35 36
 
36 37
     def get_urls(self):
37 38
         urlpatterns = super(ReviewsApplication, self).get_urls()
38
-        urlpatterns += patterns('',
39
+        urls = [
39 40
             url(r'^(?P<product_slug>[\w-]*)_(?P<product_pk>\d+)/reviews/',
40 41
                 include(self.reviews_app.urls)),
41
-        )
42
+        ]
43
+        urlpatterns += patterns('', *urls)
42 44
         return self.post_process_urls(urlpatterns)
43 45
 
44 46
 

+ 7
- 9
oscar/apps/catalogue/managers.py Datei anzeigen

@@ -7,15 +7,13 @@ class ProductManager(models.Manager):
7 7
         """
8 8
         Return ``QuerySet`` with related content pre-loaded.
9 9
         """
10
-        return self.get_query_set().select_related(
11
-            'product_class',
12
-            ).prefetch_related(
13
-            'variants',
14
-            'product_options',
15
-            'product_class__options',
16
-            'stockrecords',
17
-            'images',
18
-            ).all()
10
+        return self.get_query_set().select_related('product_class')\
11
+            .prefetch_related('variants',
12
+                              'product_options',
13
+                              'product_class__options',
14
+                              'stockrecords',
15
+                              'images',
16
+                              ).all()
19 17
 
20 18
 
21 19
 class BrowsableProductManager(ProductManager):

+ 2
- 2
oscar/apps/catalogue/models.py Datei anzeigen

@@ -1,7 +1,7 @@
1 1
 """
2 2
 Vanilla product models
3 3
 """
4
-from oscar.apps.catalogue.abstract_models import *
4
+from oscar.apps.catalogue.abstract_models import *  # noqa
5 5
 
6 6
 
7 7
 class ProductClass(AbstractProductClass):
@@ -63,4 +63,4 @@ class Option(AbstractOption):
63 63
 class ProductImage(AbstractProductImage):
64 64
     pass
65 65
 
66
-from .receivers import *
66
+from .receivers import *  # noqa

+ 3
- 1
oscar/apps/catalogue/reviews/abstract_models.py Datei anzeigen

@@ -45,7 +45,9 @@ class AbstractProductReview(models.Model):
45 45
         (APPROVED, _("Approved")),
46 46
         (REJECTED, _("Rejected")),
47 47
     )
48
-    default_status = FOR_MODERATION if settings.OSCAR_MODERATE_REVIEWS else APPROVED
48
+    default_status = APPROVED
49
+    if settings.OSCAR_MODERATE_REVIEWS:
50
+        default_status = FOR_MODERATION
49 51
     status = models.SmallIntegerField(
50 52
         _("Status"), choices=STATUS_CHOICES, default=default_status)
51 53
 

+ 2
- 1
oscar/apps/catalogue/reviews/admin.py Datei anzeigen

@@ -4,7 +4,8 @@ from oscar.apps.catalogue.reviews.models import ProductReview, Vote
4 4
 
5 5
 
6 6
 class ProductReviewAdmin(admin.ModelAdmin):
7
-    list_display = ('product', 'title', 'score', 'status', 'total_votes', 'delta_votes', 'date_created')
7
+    list_display = ('product', 'title', 'score', 'status', 'total_votes',
8
+                    'delta_votes', 'date_created')
8 9
     readonly_fields = ('total_votes', 'delta_votes')
9 10
 
10 11
 

+ 3
- 3
oscar/apps/catalogue/reviews/app.py Datei anzeigen

@@ -14,15 +14,15 @@ class ProductReviewsApplication(Application):
14 14
     list_view = views.ProductReviewList
15 15
 
16 16
     def get_urls(self):
17
-        urlpatterns = patterns('',
17
+        urls = [
18 18
             url(r'^(?P<pk>\d+)/$', self.detail_view.as_view(),
19 19
                 name='reviews-detail'),
20 20
             url(r'^add/$', self.create_view.as_view(), name='reviews-add'),
21 21
             url(r'^(?P<pk>\d+)/vote/$', self.vote_view.as_view(),
22 22
                 name='reviews-vote'),
23 23
             url(r'^$', self.list_view.as_view(), name='reviews-list'),
24
-        )
25
-        return self.post_process_urls(urlpatterns)
24
+        ]
25
+        return self.post_process_urls(patterns('', *urls))
26 26
 
27 27
 
28 28
 application = ProductReviewsApplication()

+ 8
- 5
oscar/apps/catalogue/reviews/managers.py Datei anzeigen

@@ -3,20 +3,23 @@ from django.db import models
3 3
 
4 4
 class ApprovedReviewsManager(models.Manager):
5 5
     def get_query_set(self):
6
-        return super(ApprovedReviewsManager, self).get_query_set().filter(status=1)
7
-
6
+        queryset = super(ApprovedReviewsManager, self).get_query_set()
7
+        return queryset.filter(status=1)
8 8
 
9 9
 
10 10
 class RecentReviewsManager(models.Manager):
11 11
     def get_query_set(self):
12
-        return super(RecentReviewsManager, self).get_query_set().filter(approved=True).order_by('-date_created')
12
+        queryset = super(RecentReviewsManager, self).get_query_set()
13
+        return queryset.filter(approved=True).order_by('-date_created')
13 14
 
14 15
 
15 16
 class TopScoredReviewsManager(models.Manager):
16 17
     def get_query_set(self):
17
-        return super(TopScoredReviewsManager, self).get_query_set().filter(approved=True).order_by('-score')
18
+        queryset = super(TopScoredReviewsManager, self).get_query_set()
19
+        return queryset.filter(approved=True).order_by('-score')
18 20
 
19 21
 
20 22
 class TopVotedReviewsManager(models.Manager):
21 23
     def get_query_set(self):
22
-        return super(TopVotedReviewsManager, self).get_query_set().filter(approved=True).order_by('-delta_votes')
24
+        queryset = super(TopVotedReviewsManager, self).get_query_set()
25
+        return queryset.filter(approved=True).order_by('-delta_votes')

+ 2
- 1
oscar/apps/catalogue/reviews/models.py Datei anzeigen

@@ -1,4 +1,5 @@
1
-from oscar.apps.catalogue.reviews.abstract_models import AbstractProductReview, AbstractVote
1
+from oscar.apps.catalogue.reviews.abstract_models import \
2
+    AbstractProductReview, AbstractVote
2 3
 
3 4
 
4 5
 class ProductReview(AbstractProductReview):

+ 2
- 1
oscar/apps/catalogue/reviews/views.py Datei anzeigen

@@ -100,7 +100,8 @@ class ProductReviewList(ListView):
100 100
 
101 101
     def get_queryset(self):
102 102
         qs = self.model.approved.filter(product=self.kwargs['product_pk'])
103
-        if 'sort_by' in self.request.GET and self.request.GET['sort_by'] == 'score':
103
+        if 'sort_by' in self.request.GET \
104
+                and self.request.GET['sort_by'] == 'score':
104 105
             return qs.order_by('-score')
105 106
         return qs.order_by('-date_created')
106 107
 

+ 20
- 9
oscar/apps/catalogue/utils.py Datei anzeigen

@@ -38,21 +38,29 @@ class Importer(object):
38 38
         if image_dir:
39 39
             for filename in filenames:
40 40
                 try:
41
-                    lookup_value = self._get_lookup_value_from_filename(filename)
41
+                    lookup_value \
42
+                        = self._get_lookup_value_from_filename(filename)
42 43
                     self._process_image(image_dir, filename, lookup_value)
43 44
                     stats['num_processed'] += 1
44 45
                 except Product.MultipleObjectsReturned:
45
-                    self.logger.warning("Multiple products matching %s='%s', skipping" % (self._field, lookup_value))
46
+                    self.logger.warning("Multiple products matching %s='%s',"
47
+                                        " skipping"
48
+                                        % (self._field, lookup_value))
46 49
                     stats['num_skipped'] += 1
47 50
                 except Product.DoesNotExist:
48
-                    self.logger.warning("No item matching %s='%s'" % (self._field, lookup_value))
51
+                    self.logger.warning("No item matching %s='%s'"
52
+                                        % (self._field, lookup_value))
49 53
                     stats['num_skipped'] += 1
50 54
                 except IdenticalImageError:
51
-                    self.logger.warning(" - Identical image already exists for %s='%s', skipping" % (self._field, lookup_value))
55
+                    self.logger.warning(" - Identical image already exists for"
56
+                                        " %s='%s', skipping"
57
+                                        % (self._field, lookup_value))
52 58
                     stats['num_skipped'] += 1
53 59
                 except IOError, e:
54
-                    raise ImageImportError(_('%(filename)s is not a valid image (%(error)s)') % {
55
-                        'filename': filename, 'error': e})
60
+                    raise ImageImportError(_('%(filename)s is not a valid'
61
+                                             ' image (%(error)s)')
62
+                                           % {'filename': filename,
63
+                                              'error': e})
56 64
                     stats['num_invalid'] += 1
57 65
                 except FieldError, e:
58 66
                     raise ImageImportError(e)
@@ -60,8 +68,10 @@ class Importer(object):
60 68
             if image_dir != dirname:
61 69
                 shutil.rmtree(image_dir)
62 70
         else:
63
-            raise InvalidImageArchive(_('%s is not a valid image archive') % dirname)
64
-        self.logger.info("Finished image import: %(num_processed)d imported, %(num_skipped)d skipped" % stats)
71
+            raise InvalidImageArchive(_('%s is not a valid image archive')
72
+                                      % dirname)
73
+        self.logger.info("Finished image import: %(num_processed)d imported,"
74
+                         " %(num_skipped)d skipped" % stats)
65 75
 
66 76
     def _get_image_files(self, dirname):
67 77
         filenames = []
@@ -69,7 +79,8 @@ class Importer(object):
69 79
         if image_dir:
70 80
             for filename in os.listdir(image_dir):
71 81
                 ext = os.path.splitext(filename)[1]
72
-                if os.path.isfile(os.path.join(image_dir, filename)) and ext in self.allowed_extensions:
82
+                if os.path.isfile(os.path.join(image_dir, filename)) \
83
+                        and ext in self.allowed_extensions:
73 84
                     filenames.append(filename)
74 85
         return image_dir, filenames
75 86
 

+ 6
- 4
oscar/apps/catalogue/views.py Datei anzeigen

@@ -124,8 +124,8 @@ class ProductCategoryView(ListView):
124 124
         if 'pk' in self.kwargs:
125 125
             self.category = get_object_or_404(Category, pk=self.kwargs['pk'])
126 126
         else:
127
-            self.category = get_object_or_404(Category,
128
-                                              slug=self.kwargs['category_slug'])
127
+            self.category = get_object_or_404(
128
+                Category, slug=self.kwargs['category_slug'])
129 129
 
130 130
     def get(self, request, *args, **kwargs):
131 131
         self.get_object()
@@ -176,7 +176,8 @@ class ProductListView(ListView):
176 176
         qs = Product.browsable.base_queryset()
177 177
         if q:
178 178
             # Send signal to record the view of this product
179
-            self.search_signal.send(sender=self, query=q, user=self.request.user)
179
+            self.search_signal.send(sender=self, query=q,
180
+                                    user=self.request.user)
180 181
             return qs.filter(title__icontains=q)
181 182
         else:
182 183
             return qs
@@ -187,6 +188,7 @@ class ProductListView(ListView):
187 188
         if not q:
188 189
             context['summary'] = _('All products')
189 190
         else:
190
-            context['summary'] = _("Products matching '%(query)s'") % {'query': q}
191
+            context['summary'] = _("Products matching '%(query)s'") \
192
+                % {'query': q}
191 193
             context['search_term'] = q
192 194
         return context

+ 3
- 3
oscar/apps/checkout/app.py Datei anzeigen

@@ -19,7 +19,7 @@ class CheckoutApplication(Application):
19 19
     thankyou_view = views.ThankYouView
20 20
 
21 21
     def get_urls(self):
22
-        urlpatterns = patterns('',
22
+        urls = [
23 23
             url(r'^$', self.index_view.as_view(), name='index'),
24 24
 
25 25
             # Shipping/user address views
@@ -48,8 +48,8 @@ class CheckoutApplication(Application):
48 48
                 name='preview'),
49 49
             url(r'thank-you/$', self.thankyou_view.as_view(),
50 50
                 name='thank-you'),
51
-        )
52
-        return self.post_process_urls(urlpatterns)
51
+        ]
52
+        return self.post_process_urls(patterns('', *urls))
53 53
 
54 54
     def get_url_decorator(self, pattern):
55 55
         if not settings.OSCAR_ALLOW_ANON_CHECKOUT:

+ 4
- 1
oscar/apps/checkout/context_processors.py Datei anzeigen

@@ -1,4 +1,7 @@
1 1
 from django.conf import settings
2 2
 
3
+
3 4
 def checkout(request):
4
-    return {'anon_checkout_allowed': getattr(settings, 'OSCAR_ALLOW_ANON_CHECKOUT', False)}
5
+    anon_checkout_allowed \
6
+        = getattr(settings, 'OSCAR_ALLOW_ANON_CHECKOUT', False)
7
+    return {'anon_checkout_allowed': anon_checkout_allowed}

+ 7
- 6
oscar/apps/checkout/decorators.py Datei anzeigen

@@ -11,14 +11,15 @@ def prev_steps_must_be_complete(view_fn):
11 11
     """
12 12
     Decorator for checking that previous steps of the checkout
13 13
     are complete.
14
-    
14
+
15 15
     The completed steps (identified by URL-names) are stored in the session.
16 16
     If this fails, then we redirect to the next uncompleted step.
17 17
     """
18 18
     def _view_wrapper(self, request, *args, **kwargs):
19 19
         checker = ProgressChecker()
20 20
         if not checker.are_previous_steps_complete(request):
21
-            messages.error(request, _("You must complete this step of the checkout first"))
21
+            messages.error(request, _("You must complete this step of the"
22
+                                      " checkout first"))
22 23
             url_name = checker.get_next_step(request)
23 24
             return HttpResponseRedirect(reverse(url_name))
24 25
         return view_fn(self, request, *args, **kwargs)
@@ -31,10 +32,10 @@ def basket_required(view_fn):
31 32
     or has a frozen one in the session
32 33
     """
33 34
     def _view_wrapper(self, request, *args, **kwargs):
34
-        if request.basket.is_empty and not 'checkout_basket_id' in request.session:
35
-            messages.error(request, _("You must add some products to your basket before checking out"))
35
+        if request.basket.is_empty \
36
+                and not 'checkout_basket_id' in request.session:
37
+            messages.error(request, _("You must add some products to your"
38
+                                      " basket before checking out"))
36 39
             return HttpResponseRedirect(reverse('oscar-basket'))
37 40
         return view_fn(self, request, *args, **kwargs)
38 41
     return _view_wrapper
39
-
40
-

+ 2
- 1
oscar/apps/checkout/mixins.py Datei anzeigen

@@ -206,7 +206,8 @@ class OrderPlacementMixin(CheckoutSessionMixin):
206 206
         shipping_addr.save()
207 207
         return shipping_addr
208 208
 
209
-    def create_billing_address(self, billing_address=None, shipping_address=None, **kwargs):
209
+    def create_billing_address(self, billing_address=None,
210
+                               shipping_address=None, **kwargs):
210 211
         """
211 212
         Saves any relevant billing data (eg a billing address).
212 213
         """

+ 4
- 3
oscar/apps/checkout/utils.py Datei anzeigen

@@ -76,14 +76,16 @@ class CheckoutSessionData(object):
76 76
 
77 77
     def ship_to_user_address(self, address):
78 78
         """
79
-        Set existing shipping address id to session and unset address fields from session
79
+        Set existing shipping address id to session and unset address fields
80
+        from session
80 81
         """
81 82
         self.reset_shipping_data()
82 83
         self._set('shipping', 'user_address_id', address.id)
83 84
 
84 85
     def ship_to_new_address(self, address_fields):
85 86
         """
86
-        Set new shipping address details to session and unset shipping address id
87
+        Set new shipping address details to session and unset shipping address
88
+        id
87 89
         """
88 90
         self._unset('shipping', 'new_address_fields')
89 91
         self._set('shipping', 'new_address_fields', address_fields)
@@ -225,4 +227,3 @@ class CheckoutSessionData(object):
225 227
 
226 228
     def get_submitted_basket_id(self):
227 229
         return self._get('submission', 'basket_id')
228
-

+ 57
- 31
oscar/apps/checkout/views.py Datei anzeigen

@@ -13,14 +13,19 @@ from django.views.generic import (DetailView, TemplateView, FormView,
13 13
 from oscar.apps.shipping.methods import NoShippingRequired
14 14
 from oscar.core.loading import get_class, get_classes
15 15
 
16
-ShippingAddressForm, GatewayForm = get_classes('checkout.forms', ['ShippingAddressForm', 'GatewayForm'])
17
-pre_payment, post_payment = get_classes('checkout.signals', ['pre_payment', 'post_payment'])
18
-OrderNumberGenerator, OrderCreator = get_classes('order.utils', ['OrderNumberGenerator', 'OrderCreator'])
16
+ShippingAddressForm, GatewayForm \
17
+    = get_classes('checkout.forms', ['ShippingAddressForm', 'GatewayForm'])
18
+pre_payment, post_payment \
19
+    = get_classes('checkout.signals', ['pre_payment', 'post_payment'])
20
+OrderNumberGenerator, OrderCreator \
21
+    = get_classes('order.utils', ['OrderNumberGenerator', 'OrderCreator'])
19 22
 UserAddressForm = get_class('address.forms', 'UserAddressForm')
20 23
 Repository = get_class('shipping.repository', 'Repository')
21 24
 AccountAuthView = get_class('customer.views', 'AccountAuthView')
22
-RedirectRequired, UnableToTakePayment, PaymentError = get_classes(
23
-    'payment.exceptions', ['RedirectRequired', 'UnableToTakePayment', 'PaymentError'])
25
+RedirectRequired, UnableToTakePayment, PaymentError \
26
+    = get_classes('payment.exceptions', ['RedirectRequired',
27
+                                         'UnableToTakePayment',
28
+                                         'PaymentError'])
24 29
 UnableToPlaceOrder = get_class('order.exceptions', 'UnableToPlaceOrder')
25 30
 OrderPlacementMixin = get_class('checkout.mixins', 'OrderPlacementMixin')
26 31
 CheckoutSessionMixin = get_class('checkout.session', 'CheckoutSessionMixin')
@@ -102,13 +107,14 @@ class ShippingAddressView(CheckoutSessionMixin, FormView):
102 107
     Determine the shipping address for the order.
103 108
 
104 109
     The default behaviour is to display a list of addresses from the users's
105
-    address book, from which the user can choose one to be their shipping address.
106
-    They can add/edit/delete these USER addresses.  This address will be
107
-    automatically converted into a SHIPPING address when the user checks out.
110
+    address book, from which the user can choose one to be their shipping
111
+    address.  They can add/edit/delete these USER addresses.  This address will
112
+    be automatically converted into a SHIPPING address when the user checks
113
+    out.
108 114
 
109 115
     Alternatively, the user can enter a SHIPPING address directly which will be
110
-    saved in the session and later saved as ShippingAddress model when the order
111
-    is sucessfully submitted.
116
+    saved in the session and later saved as ShippingAddress model when the
117
+    order is sucessfully submitted.
112 118
     """
113 119
     template_name = 'checkout/shipping_address.html'
114 120
     form_class = ShippingAddressForm
@@ -116,18 +122,22 @@ class ShippingAddressView(CheckoutSessionMixin, FormView):
116 122
     def get(self, request, *args, **kwargs):
117 123
         # Check that the user's basket is not empty
118 124
         if request.basket.is_empty:
119
-            messages.error(request, _("You need to add some items to your basket to checkout"))
125
+            messages.error(request, _("You need to add some items to your"
126
+                                      " basket to checkout"))
120 127
             return HttpResponseRedirect(reverse('basket:summary'))
121 128
 
122 129
         # Check that guests have entered an email address
123
-        if not request.user.is_authenticated() and not self.checkout_session.get_guest_email():
124
-            messages.error(request, _("Please either sign in or enter your email address"))
130
+        if not request.user.is_authenticated() \
131
+                and not self.checkout_session.get_guest_email():
132
+            messages.error(request, _("Please either sign in or enter your"
133
+                                      " email address"))
125 134
             return HttpResponseRedirect(reverse('checkout:index'))
126 135
 
127
-        # Check to see that a shipping address is actually required.  It may not be if
128
-        # the basket is purely downloads
136
+        # Check to see that a shipping address is actually required.  It may
137
+        # not be if the basket is purely downloads
129 138
         if not request.basket.is_shipping_required():
130
-            messages.info(request, _("Your basket does not require a shipping address to be submitted"))
139
+            messages.info(request, _("Your basket does not require a shipping"
140
+                                     " address to be submitted"))
131 141
             return HttpResponseRedirect(self.get_success_url())
132 142
 
133 143
         return super(ShippingAddressView, self).get(request, *args, **kwargs)
@@ -145,12 +155,13 @@ class ShippingAddressView(CheckoutSessionMixin, FormView):
145 155
     def get_available_addresses(self):
146 156
         return self.request.user.addresses.filter(
147 157
             country__is_shipping_country=True).order_by(
148
-                '-is_default_for_shipping')
158
+            '-is_default_for_shipping')
149 159
 
150 160
     def post(self, request, *args, **kwargs):
151 161
         # Check if a shipping address was selected directly (eg no form was
152 162
         # filled in)
153
-        if self.request.user.is_authenticated() and 'address_id' in self.request.POST:
163
+        if self.request.user.is_authenticated() \
164
+                and 'address_id' in self.request.POST:
154 165
             address = UserAddress._default_manager.get(
155 166
                 pk=self.request.POST['address_id'], user=self.request.user)
156 167
             action = self.request.POST.get('action', None)
@@ -161,8 +172,10 @@ class ShippingAddressView(CheckoutSessionMixin, FormView):
161 172
             elif action == 'delete':
162 173
                 # Delete the selected address
163 174
                 address.delete()
164
-                messages.info(self.request, _("Address deleted from your address book"))
165
-                return HttpResponseRedirect(reverse('checkout:shipping-method'))
175
+                messages.info(self.request, _("Address deleted from your"
176
+                                              " address book"))
177
+                return HttpResponseRedirect(
178
+                    reverse('checkout:shipping-method'))
166 179
             else:
167 180
                 return HttpResponseBadRequest()
168 181
         else:
@@ -237,12 +250,14 @@ class ShippingMethodView(CheckoutSessionMixin, TemplateView):
237 250
     def get(self, request, *args, **kwargs):
238 251
         # Check that the user's basket is not empty
239 252
         if request.basket.is_empty:
240
-            messages.error(request, _("You need to add some items to your basket to checkout"))
253
+            messages.error(request, _("You need to add some items to your"
254
+                                      " basket to checkout"))
241 255
             return HttpResponseRedirect(reverse('basket:summary'))
242 256
 
243 257
         # Check that shipping is required at all
244 258
         if not request.basket.is_shipping_required():
245
-            self.checkout_session.use_shipping_method(NoShippingRequired().code)
259
+            self.checkout_session.use_shipping_method(
260
+                NoShippingRequired().code)
246 261
             return self.get_success_response()
247 262
 
248 263
         # Check that shipping address has been completed
@@ -255,10 +270,13 @@ class ShippingMethodView(CheckoutSessionMixin, TemplateView):
255 270
         self._methods = self.get_available_shipping_methods()
256 271
         if len(self._methods) == 0:
257 272
             # No shipping methods available for given address
258
-            messages.warning(request, _("Shipping is unavailable for your chosen address - please choose another"))
273
+            messages.warning(request, _("Shipping is unavailable for your"
274
+                                        " chosen address - please choose"
275
+                                        " another"))
259 276
             return HttpResponseRedirect(reverse('checkout:shipping-address'))
260 277
         elif len(self._methods) == 1:
261
-            # Only one shipping method - set this and redirect onto the next step
278
+            # Only one shipping method - set this and redirect onto the next
279
+            # step
262 280
             self.checkout_session.use_shipping_method(self._methods[0].code)
263 281
             return self.get_success_response()
264 282
 
@@ -292,7 +310,8 @@ class ShippingMethodView(CheckoutSessionMixin, TemplateView):
292 310
             if method.code == method_code:
293 311
                 is_valid = True
294 312
         if not is_valid:
295
-            messages.error(request, _("Your submitted shipping method is not permitted"))
313
+            messages.error(request, _("Your submitted shipping method is not"
314
+                                      " permitted"))
296 315
             return HttpResponseRedirect(reverse('checkout:shipping-method'))
297 316
 
298 317
         # Save the code for the chosen shipping method in the session
@@ -320,18 +339,22 @@ class PaymentMethodView(CheckoutSessionMixin, TemplateView):
320 339
     def get(self, request, *args, **kwargs):
321 340
         # Check that the user's basket is not empty
322 341
         if request.basket.is_empty:
323
-            messages.error(request, _("You need to add some items to your basket to checkout"))
342
+            messages.error(request, _("You need to add some items to your"
343
+                                      " basket to checkout"))
324 344
             return HttpResponseRedirect(reverse('basket:summary'))
325 345
 
326 346
         shipping_required = request.basket.is_shipping_required()
327 347
 
328 348
         # Check that shipping address has been completed
329
-        if shipping_required and not self.checkout_session.is_shipping_address_set():
349
+        if shipping_required \
350
+                and not self.checkout_session.is_shipping_address_set():
330 351
             messages.error(request, _("Please choose a shipping address"))
331 352
             return HttpResponseRedirect(reverse('checkout:shipping-address'))
332 353
 
333 354
         # Check that shipping method has been set
334
-        if shipping_required and not self.checkout_session.is_shipping_method_set(self.request.basket):
355
+        if shipping_required \
356
+                and not self.checkout_session.is_shipping_method_set(
357
+                    self.request.basket):
335 358
             messages.error(request, _("Please choose a shipping method"))
336 359
             return HttpResponseRedirect(reverse('checkout:shipping-method'))
337 360
 
@@ -667,13 +690,16 @@ class ThankYouView(DetailView):
667 690
         order = None
668 691
         if self.request.user.is_superuser:
669 692
             if 'order_number' in self.request.GET:
670
-                order = Order._default_manager.get(number=self.request.GET['order_number'])
693
+                order = Order._default_manager.get(
694
+                    number=self.request.GET['order_number'])
671 695
             elif 'order_id' in self.request.GET:
672
-                order = Order._default_manager.get(id=self.request.GET['orderid'])
696
+                order = Order._default_manager.get(
697
+                    id=self.request.GET['orderid'])
673 698
 
674 699
         if not order:
675 700
             if 'checkout_order_id' in self.request.session:
676
-                order = Order._default_manager.get(pk=self.request.session['checkout_order_id'])
701
+                order = Order._default_manager.get(
702
+                    pk=self.request.session['checkout_order_id'])
677 703
             else:
678 704
                 raise Http404(_("No order found"))
679 705
 

+ 15
- 11
oscar/apps/customer/abstract_models.py Datei anzeigen

@@ -43,7 +43,6 @@ if hasattr(auth_models, 'BaseUserManager'):
43 43
             u.save(using=self._db)
44 44
             return u
45 45
 
46
-
47 46
     class AbstractUser(auth_models.AbstractBaseUser,
48 47
                        auth_models.PermissionsMixin):
49 48
         """
@@ -65,7 +64,8 @@ if hasattr(auth_models, 'BaseUserManager'):
65 64
             _('Active'), default=True,
66 65
             help_text=_('Designates whether this user should be treated as '
67 66
                         'active. Unselect this instead of deleting accounts.'))
68
-        date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
67
+        date_joined = models.DateTimeField(_('date joined'),
68
+                                           default=timezone.now)
69 69
 
70 70
         objects = UserManager()
71 71
 
@@ -89,7 +89,8 @@ class AbstractEmail(models.Model):
89 89
     This is a record of all emails sent to a customer.
90 90
     Normally, we only record order-related emails.
91 91
     """
92
-    user = models.ForeignKey(AUTH_USER_MODEL, related_name='emails', verbose_name=_("User"))
92
+    user = models.ForeignKey(AUTH_USER_MODEL, related_name='emails',
93
+                             verbose_name=_("User"))
93 94
     subject = models.TextField(_('Subject'), max_length=255)
94 95
     body_text = models.TextField(_("Body Text"))
95 96
     body_html = models.TextField(_("Body HTML"), blank=True, null=True)
@@ -181,7 +182,6 @@ class AbstractCommunicationEventType(models.Model):
181 182
                 except TemplateDoesNotExist:
182 183
                     templates[name] = None
183 184
 
184
-
185 185
         # Pass base URL for serving images within HTML emails
186 186
         if ctx is None:
187 187
             ctx = {}
@@ -193,7 +193,8 @@ class AbstractCommunicationEventType(models.Model):
193 193
             messages[name] = template.render(Context(ctx)) if template else ''
194 194
 
195 195
         # Ensure the email subject doesn't contain any newlines
196
-        messages['subject'] = messages['subject'].replace("\n", "").replace("\r", "")
196
+        messages['subject'] = messages['subject'].replace("\n", "")
197
+        messages['subject'] = messages['subject'].replace("\r", "")
197 198
 
198 199
         return messages
199 200
 
@@ -208,8 +209,8 @@ class AbstractCommunicationEventType(models.Model):
208 209
 
209 210
 
210 211
 class AbstractNotification(models.Model):
211
-    recipient = models.ForeignKey(AUTH_USER_MODEL, related_name='notifications',
212
-                                  db_index=True)
212
+    recipient = models.ForeignKey(AUTH_USER_MODEL,
213
+                                  related_name='notifications', db_index=True)
213 214
 
214 215
     # Not all notifications will have a sender.
215 216
     sender = models.ForeignKey(AUTH_USER_MODEL, null=True)
@@ -258,8 +259,9 @@ class AbstractProductAlert(models.Model):
258 259
     # A user is only required if the notification is created by a
259 260
     # registered user, anonymous users will only have an email address
260 261
     # attached to the notification
261
-    user = models.ForeignKey(AUTH_USER_MODEL, db_index=True, blank=True, null=True,
262
-                             related_name="alerts", verbose_name=_('User'))
262
+    user = models.ForeignKey(AUTH_USER_MODEL, db_index=True, blank=True,
263
+                             null=True, related_name="alerts",
264
+                             verbose_name=_('User'))
263 265
     email = models.EmailField(_("Email"), db_index=True, blank=True, null=True)
264 266
 
265 267
     # This key are used to confirm and cancel alerts for anon users
@@ -344,7 +346,8 @@ class AbstractProductAlert(models.Model):
344 346
         # calls save, and doesn't call the methods cancel(), confirm() etc).
345 347
         if self.status == self.CANCELLED and self.date_cancelled is None:
346 348
             self.date_cancelled = timezone.now()
347
-        if not self.user and self.status == self.ACTIVE and self.date_confirmed is None:
349
+        if not self.user and self.status == self.ACTIVE \
350
+                and self.date_confirmed is None:
348 351
             self.date_confirmed = timezone.now()
349 352
         if self.status == self.CLOSED and self.date_closed is None:
350 353
             self.date_closed = timezone.now()
@@ -362,4 +365,5 @@ class AbstractProductAlert(models.Model):
362 365
         return reverse('customer:alerts-confirm', kwargs={'key': self.key})
363 366
 
364 367
     def get_cancel_url(self):
365
-        return reverse('customer:alerts-cancel-by-key', kwargs={'key': self.key})
368
+        return reverse('customer:alerts-cancel-by-key', kwargs={'key':
369
+                                                                self.key})

+ 10
- 5
oscar/apps/customer/alerts/utils.py Datei anzeigen

@@ -36,8 +36,10 @@ def send_alert_confirmation(alert):
36 36
         'alert': alert,
37 37
         'site': Site.objects.get_current(),
38 38
     })
39
-    subject_tpl = loader.get_template('customer/alerts/emails/confirmation_subject.txt')
40
-    body_tpl = loader.get_template('customer/alerts/emails/confirmation_body.txt')
39
+    subject_tpl = loader.get_template('customer/alerts/emails/'
40
+                                      'confirmation_subject.txt')
41
+    body_tpl = loader.get_template('customer/alerts/emails/'
42
+                                   'confirmation_body.txt')
41 43
     mail.send_mail(
42 44
         subject_tpl.render(ctx).strip(),
43 45
         body_tpl.render(ctx),
@@ -74,8 +76,10 @@ def send_product_alerts(product):
74 76
 
75 77
     # Load templates
76 78
     message_tpl = loader.get_template('customer/alerts/message.html')
77
-    email_subject_tpl = loader.get_template('customer/alerts/emails/alert_subject.txt')
78
-    email_body_tpl = loader.get_template('customer/alerts/emails/alert_body.txt')
79
+    email_subject_tpl = loader.get_template('customer/alerts/emails/'
80
+                                            'alert_subject.txt')
81
+    email_body_tpl = loader.get_template('customer/alerts/emails/'
82
+                                         'alert_body.txt')
79 83
 
80 84
     emails = []
81 85
     num_notifications = 0
@@ -116,4 +120,5 @@ def send_product_alerts(product):
116 120
         connection.send_messages(emails)
117 121
         connection.close()
118 122
 
119
-    logger.info("Sent %d notifications and %d emails", num_notifications, len(emails))
123
+    logger.info("Sent %d notifications and %d emails", num_notifications,
124
+                len(emails))

+ 21
- 11
oscar/apps/customer/alerts/views.py Datei anzeigen

@@ -50,7 +50,8 @@ class ProductAlertCreateView(generic.CreateView):
50 50
 
51 51
     def post(self, request, *args, **kwargs):
52 52
         self.product = get_object_or_404(Product, pk=self.kwargs['pk'])
53
-        return super(ProductAlertCreateView, self).post(request, *args, **kwargs)
53
+        return super(ProductAlertCreateView, self).post(request, *args,
54
+                                                        **kwargs)
54 55
 
55 56
     def get_form_kwargs(self):
56 57
         kwargs = super(ProductAlertCreateView, self).get_form_kwargs()
@@ -68,7 +69,8 @@ class ProductAlertCreateView(generic.CreateView):
68 69
         if self.object.user:
69 70
             msg = _("An alert has been created")
70 71
         else:
71
-            msg = _("A confirmation email has been sent to %s") % self.object.email
72
+            msg = _("A confirmation email has been sent to %s") \
73
+                % self.object.email
72 74
         messages.success(self.request, msg)
73 75
         return self.object.product.get_absolute_url()
74 76
 
@@ -79,14 +81,16 @@ class ProductAlertConfirmView(generic.RedirectView):
79 81
     def get(self, request, *args, **kwargs):
80 82
         self.alert = get_object_or_404(ProductAlert, key=kwargs['key'])
81 83
         self.update_alert()
82
-        return super(ProductAlertConfirmView, self).get(request, *args, **kwargs)
84
+        return super(ProductAlertConfirmView, self).get(request, *args,
85
+                                                        **kwargs)
83 86
 
84 87
     def update_alert(self):
85 88
         if self.alert.can_be_confirmed:
86 89
             self.alert.confirm()
87 90
             messages.success(self.request, _("Your stock alert is now active"))
88 91
         else:
89
-            messages.error(self.request, _("Your stock alert cannot be confirmed"))
92
+            messages.error(self.request, _("Your stock alert cannot be"
93
+                                           " confirmed"))
90 94
 
91 95
     def get_redirect_url(self, **kwargs):
92 96
         return self.alert.product.get_absolute_url()
@@ -98,26 +102,32 @@ class ProductAlertCancelView(generic.RedirectView):
98 102
     anonymously created alerts) or the pk (used for alerts created by a
99 103
     authenticated user).
100 104
 
101
-    Specifying the redirect url is possible by supplying a 'next' GET parameter.
102
-    It defaults to showing the associated product page.
105
+    Specifying the redirect url is possible by supplying a 'next' GET
106
+    parameter.  It defaults to showing the associated product page.
103 107
     """
104 108
 
105 109
     def get(self, request, *args, **kwargs):
106 110
         if 'key' in kwargs:
107 111
             self.alert = get_object_or_404(ProductAlert, key=kwargs['key'])
108 112
         elif 'pk' in kwargs and request.user.is_authenticated():
109
-            self.alert = get_object_or_404(ProductAlert, user=self.request.user, pk=kwargs['pk'])
113
+            self.alert = get_object_or_404(ProductAlert,
114
+                                           user=self.request.user,
115
+                                           pk=kwargs['pk'])
110 116
         else:
111 117
             raise Http404
112 118
         self.update_alert()
113
-        return super(ProductAlertCancelView, self).get(request, *args, **kwargs)
119
+        return super(ProductAlertCancelView, self).get(request, *args,
120
+                                                       **kwargs)
114 121
 
115 122
     def update_alert(self):
116 123
         if self.alert.can_be_cancelled:
117 124
             self.alert.cancel()
118
-            messages.success(self.request, _("Your stock alert has been cancelled"))
125
+            messages.success(self.request, _("Your stock alert has been"
126
+                                             " cancelled"))
119 127
         else:
120
-            messages.error(self.request, _("Your stock alert cannot be cancelled"))
128
+            messages.error(self.request, _("Your stock alert cannot be"
129
+                                           " cancelled"))
121 130
 
122 131
     def get_redirect_url(self, **kwargs):
123
-        return self.request.GET.get('next', self.alert.product.get_absolute_url())
132
+        return self.request.GET.get('next',
133
+                                    self.alert.product.get_absolute_url())

+ 13
- 9
oscar/apps/customer/app.py Datei anzeigen

@@ -50,10 +50,11 @@ class CustomerApplication(Application):
50 50
     wishlists_update_view = wishlists_views.WishListUpdateView
51 51
     wishlists_delete_view = wishlists_views.WishListDeleteView
52 52
     wishlists_remove_product_view = wishlists_views.WishListRemoveProduct
53
-    wishlists_move_product_to_another_view = wishlists_views.WishListMoveProductToAnotherWishList
53
+    wishlists_move_product_to_another_view \
54
+        = wishlists_views.WishListMoveProductToAnotherWishList
54 55
 
55 56
     def get_urls(self):
56
-        urlpatterns = patterns('',
57
+        urls = [
57 58
             url(r'^$', login_required(self.summary_view.as_view()),
58 59
                 name='summary'),
59 60
             url(r'^login/$', self.login_view.as_view(), name='login'),
@@ -96,7 +97,8 @@ class CustomerApplication(Application):
96 97
             url(r'^addresses/(?P<pk>\d+)/delete/$',
97 98
                 login_required(self.address_delete_view.as_view()),
98 99
                 name='address-delete'),
99
-            url(r'^addresses/(?P<pk>\d+)/(?P<action>default_for_(billing|shipping))/$',
100
+            url(r'^addresses/(?P<pk>\d+)/'
101
+                r'(?P<action>default_for_(billing|shipping))/$',
100 102
                 login_required(self.address_change_status_view.as_view()),
101 103
                 name='address-change-status'),
102 104
 
@@ -168,14 +170,16 @@ class CustomerApplication(Application):
168 170
             url(r'wishlists/(?P<key>[a-z0-9]+)/lines/(?P<line_pk>\d+)/delete/',
169 171
                 login_required(self.wishlists_remove_product_view.as_view()),
170 172
                 name='wishlists-remove-product'),
171
-            url(r'wishlists/(?P<key>[a-z0-9]+)/products/(?P<product_pk>\d+)/delete/',
173
+            url(r'wishlists/(?P<key>[a-z0-9]+)/products/(?P<product_pk>\d+)/'
174
+                r'delete/',
172 175
                 login_required(self.wishlists_remove_product_view.as_view()),
173 176
                 name='wishlists-remove-product'),
174
-            url(r'wishlists/(?P<key>[a-z0-9]+)/lines/(?P<line_pk>\d+)/move-to/(?P<to_key>[a-z0-9]+)/$',
175
-                login_required(self.wishlists_move_product_to_another_view.as_view()),
176
-                name='wishlists-move-product-to-another'),
177
-            )
178
-        return self.post_process_urls(urlpatterns)
177
+            url(r'wishlists/(?P<key>[a-z0-9]+)/lines/(?P<line_pk>\d+)/move-to/'
178
+                r'(?P<to_key>[a-z0-9]+)/$',
179
+                login_required(self.wishlists_move_product_to_another_view
180
+                               .as_view()),
181
+                name='wishlists-move-product-to-another')]
182
+        return self.post_process_urls(patterns('', *urls))
179 183
 
180 184
 
181 185
 application = CustomerApplication()

+ 4
- 3
oscar/apps/customer/auth_backends.py Datei anzeigen

@@ -50,8 +50,9 @@ class Emailbackend(ModelBackend):
50 50
             # either.  This situation requires intervention by an admin and so
51 51
             # we mail them to let them know!
52 52
             mail_admins(
53
-                "There are multiple users with email address: %s" % clean_email,
53
+                "There are multiple users with email address: %s"
54
+                % clean_email,
54 55
                 ("There are %s users with email %s and the same password "
55
-                 "which means none of them are able to authenticate") % (len(authenticated_users),
56
-                                                clean_email))
56
+                 "which means none of them are able to authenticate")
57
+                % (len(authenticated_users), clean_email))
57 58
         return None

+ 4
- 2
oscar/apps/customer/forms.py Datei anzeigen

@@ -25,7 +25,8 @@ User = get_user_model()
25 25
 
26 26
 
27 27
 def generate_username():
28
-    uname = ''.join([random.choice(string.letters + string.digits + '_') for i in range(30)])
28
+    uname = ''.join([random.choice(string.letters + string.digits + '_')
29
+                     for i in range(30)])
29 30
     try:
30 31
         User.objects.get(username=uname)
31 32
         return generate_username()
@@ -93,7 +94,8 @@ class EmailAuthenticationForm(AuthenticationForm):
93 94
 
94 95
 
95 96
 class CommonPasswordValidator(validators.BaseValidator):
96
-    # See http://www.smartplanet.com/blog/business-brains/top-20-most-common-passwords-of-all-time-revealed-8216123456-8216princess-8216qwerty/4519
97
+    # See
98
+    # http://www.smartplanet.com/blog/business-brains/top-20-most-common-passwords-of-all-time-revealed-8216123456-8216princess-8216qwerty/4519  # noqa
97 99
     forbidden_passwords = [
98 100
         'password',
99 101
         '1234',

+ 0
- 3
oscar/apps/customer/mixins.py Datei anzeigen

@@ -76,6 +76,3 @@ class RegisterUserMixin(object):
76 76
             code, ctx)
77 77
         if messages and messages['body']:
78 78
             Dispatcher().dispatch_user_messages(user, messages)
79
-
80
-
81
-

+ 2
- 2
oscar/apps/customer/models.py Datei anzeigen

@@ -17,5 +17,5 @@ class ProductAlert(abstract_models.AbstractProductAlert):
17 17
     pass
18 18
 
19 19
 
20
-from oscar.apps.customer.history import *
21
-from oscar.apps.customer.alerts.receivers import *
20
+from oscar.apps.customer.history import *  # noqa
21
+from oscar.apps.customer.alerts.receivers import *  # noqa

+ 4
- 4
oscar/apps/customer/notifications/views.py Datei anzeigen

@@ -91,8 +91,8 @@ class UpdateView(BulkEditMixin, generic.RedirectView):
91 91
             notification.archive()
92 92
         msg = ungettext(
93 93
             '%(count)d notification archived',
94
-            '%(count)d notifications archived', len(notifications)) % {
95
-                'count': len(notifications)}
94
+            '%(count)d notifications archived', len(notifications)) \
95
+            % {'count': len(notifications)}
96 96
         messages.success(request, msg)
97 97
         return self.get_success_response()
98 98
 
@@ -101,7 +101,7 @@ class UpdateView(BulkEditMixin, generic.RedirectView):
101 101
             notification.delete()
102 102
         msg = ungettext(
103 103
             '%(count)d notification deleted',
104
-            '%(count)d notifications deleted', len(notifications)) % {
105
-                'count': len(notifications)}
104
+            '%(count)d notifications deleted', len(notifications)) \
105
+            % {'count': len(notifications)}
106 106
         messages.success(request, msg)
107 107
         return self.get_success_response()

+ 7
- 4
oscar/apps/customer/utils.py Datei anzeigen

@@ -59,10 +59,12 @@ class Dispatcher(object):
59 59
 
60 60
     def send_user_email_messages(self, user, messages):
61 61
         """
62
-        Sends message to the registered user / customer and collects data in database
62
+        Sends message to the registered user / customer and collects data in
63
+        database
63 64
         """
64 65
         if not user.email:
65
-            self.logger.warning("Unable to send email messages as user #%d has no email address", user.id)
66
+            self.logger.warning("Unable to send email messages as user #%d has"
67
+                                " no email address", user.id)
66 68
             return
67 69
 
68 70
         email = self.send_email_messages(user.email, messages)
@@ -115,8 +117,9 @@ def get_password_reset_url(user, token_generator=default_token_generator):
115 117
 
116 118
 def normalise_email(email):
117 119
     """
118
-    The local part of an email address is case-sensitive, the domain part isn't.
119
-    This function lowercases the host and should be used in all email handling.
120
+    The local part of an email address is case-sensitive, the domain part
121
+    isn't.  This function lowercases the host and should be used in all email
122
+    handling.
120 123
     """
121 124
     clean_email = email.strip()
122 125
     if '@' in clean_email:

+ 7
- 5
oscar/apps/customer/views.py Datei anzeigen

@@ -143,12 +143,12 @@ class AccountAuthView(RegisterUserMixin, TemplateView):
143 143
         kwargs['prefix'] = self.registration_prefix
144 144
         kwargs['initial'] = {
145 145
             'redirect_url': self.request.GET.get(self.redirect_field_name, ''),
146
-            }
146
+        }
147 147
         if request and request.method in ('POST', 'PUT'):
148 148
             kwargs.update({
149 149
                 'data': request.POST,
150 150
                 'files': request.FILES,
151
-                })
151
+            })
152 152
         return kwargs
153 153
 
154 154
     def post(self, request, *args, **kwargs):
@@ -313,7 +313,7 @@ class ChangePasswordView(PageTitleMixin, FormView):
313 313
             'user': self.request.user,
314 314
             'site': get_current_site(self.request),
315 315
             'reset_url': get_password_reset_url(self.request.user),
316
-            }
316
+        }
317 317
         msgs = CommunicationEventType.objects.get_and_render(
318 318
             code=self.communication_type_code, context=ctx)
319 319
         Dispatcher().dispatch_user_messages(self.request.user, msgs)
@@ -496,7 +496,8 @@ class OrderLineView(PostActionMixin, DetailView):
496 496
 
497 497
     def do_reorder(self, line):
498 498
         self.response = HttpResponseRedirect(
499
-            reverse('customer:order', args=(int(self.kwargs['order_number']),)))
499
+            reverse('customer:order',
500
+                    args=(int(self.kwargs['order_number']),)))
500 501
         basket = self.request.basket
501 502
 
502 503
         line_available_to_reorder, reason = line.is_available_to_reorder(
@@ -519,7 +520,8 @@ class OrderLineView(PostActionMixin, DetailView):
519 520
         basket.add_product(line.product, line.quantity, options)
520 521
 
521 522
         if line.quantity > 1:
522
-            msg = _("%(qty)d copies of '%(product)s' have been added to your basket") % {
523
+            msg = _("%(qty)d copies of '%(product)s' have been added to your"
524
+                    " basket") % {
523 525
                 'qty': line.quantity, 'product': line.product}
524 526
         else:
525 527
             msg = _("'%s' has been added to your basket") % line.product

+ 11
- 7
oscar/apps/customer/wishlists/views.py Datei anzeigen

@@ -6,7 +6,8 @@ from django.core.urlresolvers import reverse
6 6
 from django.db.models import get_model
7 7
 from django.http import Http404, HttpResponseRedirect
8 8
 from django.shortcuts import get_object_or_404
9
-from django.views.generic import ListView, CreateView, UpdateView, DeleteView, View, FormView
9
+from django.views.generic import (ListView, CreateView, UpdateView, DeleteView,
10
+                                  View, FormView)
10 11
 from django.utils.translation import ugettext_lazy as _
11 12
 
12 13
 from oscar.apps.customer.mixins import PageTitleMixin
@@ -41,7 +42,8 @@ class WishListDetailView(PageTitleMixin, FormView):
41 42
 
42 43
     def dispatch(self, request, *args, **kwargs):
43 44
         self.object = self.get_wishlist_or_404(kwargs['key'], request.user)
44
-        return super(WishListDetailView, self).dispatch(request, *args, **kwargs)
45
+        return super(WishListDetailView, self).dispatch(request, *args,
46
+                                                        **kwargs)
45 47
 
46 48
     def get_wishlist_or_404(self, key, user):
47 49
         wishlist = get_object_or_404(WishList, key=key)
@@ -74,7 +76,7 @@ class WishListDetailView(PageTitleMixin, FormView):
74 76
                 subform.save()
75 77
         messages.success(self.request, _('Quantities updated.'))
76 78
         return HttpResponseRedirect(reverse('customer:wishlists-detail',
77
-                                            kwargs= {'key': self.object.key}))
79
+                                            kwargs={'key': self.object.key}))
78 80
 
79 81
 
80 82
 class WishListCreateView(PageTitleMixin, CreateView):
@@ -117,8 +119,8 @@ class WishListCreateView(PageTitleMixin, CreateView):
117 119
         if self.product:
118 120
             wishlist.add(self.product)
119 121
             msg = _("Your wishlist has been created and '%(name)s "
120
-                    "has been added") % {
121
-                        'name': self.product.get_title()}
122
+                    "has been added") \
123
+                % {'name': self.product.get_title()}
122 124
         else:
123 125
             msg = _("Your wishlist has been created")
124 126
         messages.success(self.request, msg)
@@ -169,7 +171,8 @@ class WishListUpdateView(PageTitleMixin, UpdateView):
169 171
 
170 172
     def get_success_url(self):
171 173
         messages.success(
172
-            self.request, _("Your '%s' wishlist has been updated") % self.object.name)
174
+            self.request, _("Your '%s' wishlist has been updated")
175
+            % self.object.name)
173 176
         return reverse('customer:wishlists-list')
174 177
 
175 178
 
@@ -187,7 +190,8 @@ class WishListDeleteView(PageTitleMixin, DeleteView):
187 190
 
188 191
     def get_success_url(self):
189 192
         messages.success(
190
-            self.request, _("Your '%s' wish list has been deleted") % self.object.name)
193
+            self.request, _("Your '%s' wish list has been deleted")
194
+            % self.object.name)
191 195
         return reverse('customer:wishlists-list')
192 196
 
193 197
 

+ 3
- 3
oscar/apps/dashboard/app.py Datei anzeigen

@@ -26,7 +26,7 @@ class DashboardApplication(Application):
26 26
     comms_app = get_class('dashboard.communications.app', 'application')
27 27
 
28 28
     def get_urls(self):
29
-        urlpatterns = patterns('',
29
+        urls = [
30 30
             url(r'^$', self.index_view.as_view(), name='index'),
31 31
             url(r'^catalogue/', include(self.catalogue_app.urls)),
32 32
             url(r'^reports/', include(self.reports_app.urls)),
@@ -40,8 +40,8 @@ class DashboardApplication(Application):
40 40
             url(r'^reviews/', include(self.reviews_app.urls)),
41 41
             url(r'^vouchers/', include(self.vouchers_app.urls)),
42 42
             url(r'^comms/', include(self.comms_app.urls)),
43
-        )
44
-        return self.post_process_urls(urlpatterns)
43
+        ]
44
+        return self.post_process_urls(patterns('', *urls))
45 45
 
46 46
 
47 47
 application = DashboardApplication()

+ 11
- 8
oscar/apps/dashboard/catalogue/app.py Datei anzeigen

@@ -9,11 +9,14 @@ class CatalogueApplication(Application):
9 9
 
10 10
     default_permissions = ['is_staff', ]
11 11
     permissions_map = _map = {
12
-        'catalogue-product':        (['is_staff'], ['partner.dashboard_access']),
13
-        'catalogue-product-create': (['is_staff'], ['partner.dashboard_access']),
14
-        'catalogue-product-list':   (['is_staff'], ['partner.dashboard_access']),
15
-        'catalogue-product-delete': (['is_staff'], ['partner.dashboard_access']),
16
-        'catalogue-product-lookup': (['is_staff'], ['partner.dashboard_access']),
12
+        'catalogue-product': (['is_staff'], ['partner.dashboard_access']),
13
+        'catalogue-product-create': (['is_staff'],
14
+                                     ['partner.dashboard_access']),
15
+        'catalogue-product-list': (['is_staff'], ['partner.dashboard_access']),
16
+        'catalogue-product-delete': (['is_staff'],
17
+                                     ['partner.dashboard_access']),
18
+        'catalogue-product-lookup': (['is_staff'],
19
+                                     ['partner.dashboard_access']),
17 20
     }
18 21
 
19 22
     product_list_view = views.ProductListView
@@ -31,7 +34,7 @@ class CatalogueApplication(Application):
31 34
     stock_alert_view = views.StockAlertListView
32 35
 
33 36
     def get_urls(self):
34
-        urlpatterns = patterns('',
37
+        urls = [
35 38
             url(r'^products/(?P<pk>\d+)/$',
36 39
                 self.product_createupdate_view.as_view(),
37 40
                 name='catalogue-product'),
@@ -63,8 +66,8 @@ class CatalogueApplication(Application):
63 66
             url(r'^categories/(?P<pk>\d+)/delete/$',
64 67
                 self.category_delete_view.as_view(),
65 68
                 name='catalogue-category-delete'),
66
-        )
67
-        return self.post_process_urls(urlpatterns)
69
+        ]
70
+        return self.post_process_urls(patterns('', *urls))
68 71
 
69 72
 
70 73
 application = CatalogueApplication()

+ 12
- 6
oscar/apps/dashboard/catalogue/forms.py Datei anzeigen

@@ -18,7 +18,8 @@ ProductCategory = get_model('catalogue', 'ProductCategory')
18 18
 ProductImage = get_model('catalogue', 'ProductImage')
19 19
 ProductRecommendation = get_model('catalogue', 'ProductRecommendation')
20 20
 ProductSelect = get_class('dashboard.catalogue.widgets', 'ProductSelect')
21
-ProductSelectMultiple = get_class('dashboard.catalogue.widgets', 'ProductSelectMultiple')
21
+ProductSelectMultiple = get_class('dashboard.catalogue.widgets',
22
+                                  'ProductSelectMultiple')
22 23
 
23 24
 
24 25
 class BaseCategoryForm(MoveNodeForm):
@@ -47,7 +48,9 @@ class BaseCategoryForm(MoveNodeForm):
47 48
             parent = None
48 49
 
49 50
         # build full slug
50
-        slug_prefix = (parent.slug + Category._slug_separator) if parent else ''
51
+        slug_prefix = ''
52
+        if parent:
53
+            slug_prefix = (parent.slug + Category._slug_separator)
51 54
         slug = '%s%s' % (slug_prefix, slugify(name))
52 55
 
53 56
         # check if slug is conflicting
@@ -141,7 +144,10 @@ class StockRecordFormSet(BaseStockRecordFormSet):
141 144
                                         for form in self.forms])
142 145
             user_partners = set(self.user.partners.all())
143 146
             if not user_partners & stockrecord_partners:
144
-                raise ValidationError(_("At least one stock record must be set to a partner that you're associated with."))
147
+                raise ValidationError(_("At least one stock record must be set"
148
+                                        " to a partner that you're associated"
149
+                                        " with."))
150
+
145 151
 
146 152
 def _attr_text_field(attribute):
147 153
     return forms.CharField(label=attribute.name,
@@ -258,8 +264,8 @@ class ProductForm(forms.ModelForm):
258 264
 
259 265
     def add_attribute_fields(self):
260 266
         for attribute in self.product_class.attributes.all():
261
-            self.fields['attr_%s' % attribute.code] = \
262
-                    self.get_attribute_field(attribute)
267
+            self.fields['attr_%s' % attribute.code] \
268
+                = self.get_attribute_field(attribute)
263 269
 
264 270
     def get_attribute_field(self, attribute):
265 271
         return self.FIELD_FACTORIES[attribute.type](attribute)
@@ -334,7 +340,7 @@ class BaseProductCategoryFormSet(BaseInlineFormSet):
334 340
             form = self.forms[i]
335 341
             if (hasattr(form, 'cleaned_data')
336 342
                     and form.cleaned_data.get('category', None)
337
-                    and form.cleaned_data.get('DELETE', False) != True):
343
+                    and not form.cleaned_data.get('DELETE', False)):
338 344
                 num_categories += 1
339 345
         return num_categories
340 346
 

+ 22
- 17
oscar/apps/dashboard/catalogue/views.py Datei anzeigen

@@ -17,16 +17,16 @@ from oscar.views.generic import ObjectLookupView
17 17
  StockAlertSearchForm,
18 18
  ProductCategoryFormSet,
19 19
  ProductImageFormSet,
20
- ProductRecommendationFormSet) = get_classes(
21
-     'dashboard.catalogue.forms',
22
-     ('ProductForm',
23
-      'ProductSearchForm',
24
-      'CategoryForm',
25
-      'StockRecordFormSet',
26
-      'StockAlertSearchForm',
27
-      'ProductCategoryFormSet',
28
-      'ProductImageFormSet',
29
-      'ProductRecommendationFormSet'))
20
+ ProductRecommendationFormSet) \
21
+    = get_classes('dashboard.catalogue.forms',
22
+                  ('ProductForm',
23
+                   'ProductSearchForm',
24
+                   'CategoryForm',
25
+                   'StockRecordFormSet',
26
+                   'StockAlertSearchForm',
27
+                   'ProductCategoryFormSet',
28
+                   'ProductImageFormSet',
29
+                   'ProductRecommendationFormSet'))
30 30
 Product = get_model('catalogue', 'Product')
31 31
 Category = get_model('catalogue', 'Category')
32 32
 ProductImage = get_model('catalogue', 'ProductImage')
@@ -71,7 +71,8 @@ class ProductListView(generic.ListView):
71 71
         ctx['product_classes'] = ProductClass.objects.all()
72 72
         ctx['form'] = self.form
73 73
         if 'recently_edited' in self.request.GET:
74
-            ctx['queryset_description'] = _("Last %(num_products)d edited products") \
74
+            ctx['queryset_description'] \
75
+                = _("Last %(num_products)d edited products") \
75 76
                 % {'num_products': self.recent_products}
76 77
         else:
77 78
             ctx['queryset_description'] = self.description
@@ -184,11 +185,13 @@ class ProductCreateUpdateView(generic.UpdateView):
184 185
             ctx['stockrecord_formset'] = self.stockrecord_formset(
185 186
                 self.product_class, self.request.user, instance=self.object)
186 187
         if 'category_formset' not in ctx:
187
-            ctx['category_formset'] = self.category_formset(instance=self.object)
188
+            ctx['category_formset'] \
189
+                = self.category_formset(instance=self.object)
188 190
         if 'image_formset' not in ctx:
189 191
             ctx['image_formset'] = self.image_formset(instance=self.object)
190 192
         if 'recommended_formset' not in ctx:
191
-            ctx['recommended_formset'] = self.recommendations_formset(instance=self.object)
193
+            ctx['recommended_formset'] \
194
+                = self.recommendations_formset(instance=self.object)
192 195
         if self.object is None:
193 196
             ctx['title'] = _('Create new %s product') % self.product_class.name
194 197
         else:
@@ -313,7 +316,7 @@ class ProductDeleteView(generic.DeleteView):
313 316
             raise PermissionDenied
314 317
 
315 318
     def get_success_url(self):
316
-        msg =_("Deleted product '%s'") % self.object.title
319
+        msg = _("Deleted product '%s'") % self.object.title
317 320
         messages.success(self.request, msg)
318 321
         return reverse('dashboard:catalogue-product-list')
319 322
 
@@ -358,7 +361,8 @@ class CategoryDetailListView(generic.DetailView):
358 361
     context_object_name = 'category'
359 362
 
360 363
     def get_context_data(self, *args, **kwargs):
361
-        ctx = super(CategoryDetailListView, self).get_context_data(*args, **kwargs)
364
+        ctx = super(CategoryDetailListView, self).get_context_data(*args,
365
+                                                                   **kwargs)
362 366
         ctx['child_categories'] = self.object.get_children()
363 367
         ctx['ancestors'] = self.object.get_ancestors()
364 368
         return ctx
@@ -372,7 +376,7 @@ class CategoryListMixin(object):
372 376
             return reverse("dashboard:catalogue-category-list")
373 377
         else:
374 378
             return reverse("dashboard:catalogue-category-detail-list",
375
-                            args=(parent.pk,))
379
+                           args=(parent.pk,))
376 380
 
377 381
 
378 382
 class CategoryCreateView(CategoryListMixin, generic.CreateView):
@@ -426,4 +430,5 @@ class ProductLookupView(ObjectLookupView):
426 430
         return self.model.browsable.all()
427 431
 
428 432
     def lookup_filter(self, qs, term):
429
-        return qs.filter(Q(title__icontains=term) | Q(parent__title__icontains=term))
433
+        return qs.filter(Q(title__icontains=term)
434
+                         | Q(parent__title__icontains=term))

+ 3
- 3
oscar/apps/dashboard/communications/app.py Datei anzeigen

@@ -12,12 +12,12 @@ class CommsDashboardApplication(Application):
12 12
     update_view = views.UpdateView
13 13
 
14 14
     def get_urls(self):
15
-        urlpatterns = patterns('',
15
+        urls = [
16 16
             url(r'^$', self.list_view.as_view(), name='comms-list'),
17 17
             url(r'^(?P<code>\w+)/$', self.update_view.as_view(),
18 18
                 name='comms-update'),
19
-        )
20
-        return self.post_process_urls(urlpatterns)
19
+        ]
20
+        return self.post_process_urls(patterns('', *urls))
21 21
 
22 22
 
23 23
 application = CommsDashboardApplication()

+ 2
- 2
oscar/apps/dashboard/communications/views.py Datei anzeigen

@@ -33,8 +33,8 @@ class UpdateView(generic.UpdateView):
33 33
 
34 34
     def form_invalid(self, form):
35 35
         messages.error(self.request,
36
-            _("The submitted form was not valid, please correct "
37
-              "the errors and resubmit"))
36
+                       _("The submitted form was not valid, please correct "
37
+                         "the errors and resubmit"))
38 38
         return super(UpdateView, self).form_invalid(form)
39 39
 
40 40
     def form_valid(self, form):

+ 0
- 1
oscar/apps/dashboard/models.py Datei anzeigen

@@ -1 +0,0 @@
1
-

+ 5
- 4
oscar/apps/dashboard/nav.py Datei anzeigen

@@ -58,9 +58,9 @@ class Node(object):
58 58
         # We can't assume that the view has the same parent module as the app,
59 59
         # as either the app or view can be customised. So we turn the module
60 60
         # string (e.g. 'oscar.apps.dashboard.catalogue.views') into an app
61
-        # label that can be loaded by get_class (e.g. 'dashboard.catalogue.app),
62
-        # which then essentially checks INSTALLED_APPS for the right module to
63
-        # load
61
+        # label that can be loaded by get_class (e.g.
62
+        # 'dashboard.catalogue.app), which then essentially checks
63
+        # INSTALLED_APPS for the right module to load
64 64
         match = re.search('(dashboard[\w\.]*)\.views$', view_module)
65 65
         if not match:
66 66
             raise exception
@@ -90,7 +90,8 @@ class Node(object):
90 90
             return None
91 91
         node = Node(
92 92
             label=self.label, url_name=self.url_name, url_args=self.url_args,
93
-            url_kwargs=self.url_kwargs, access_fn=self.access_fn, icon=self.icon
93
+            url_kwargs=self.url_kwargs, access_fn=self.access_fn,
94
+            icon=self.icon
94 95
         )
95 96
         for child in self.children:
96 97
             if child.is_visible(user):

+ 3
- 3
oscar/apps/dashboard/offers/app.py Datei anzeigen

@@ -18,7 +18,7 @@ class OffersDashboardApplication(Application):
18 18
     detail_view = views.OfferDetailView
19 19
 
20 20
     def get_urls(self):
21
-        urlpatterns = patterns('',
21
+        urls = [
22 22
             url(r'^$', self.list_view.as_view(), name='offer-list'),
23 23
             # Creation
24 24
             url(r'^new/name-and-description/$', self.metadata_view.as_view(),
@@ -48,8 +48,8 @@ class OffersDashboardApplication(Application):
48 48
             # Stats
49 49
             url(r'^(?P<pk>\d+)/$', self.detail_view.as_view(),
50 50
                 name='offer-detail'),
51
-        )
52
-        return self.post_process_urls(urlpatterns)
51
+        ]
52
+        return self.post_process_urls(patterns('', *urls))
53 53
 
54 54
 
55 55
 application = OffersDashboardApplication()

+ 9
- 8
oscar/apps/dashboard/offers/views.py Datei anzeigen

@@ -21,10 +21,10 @@ Range = get_model('offer', 'Range')
21 21
 Product = get_model('catalogue', 'Product')
22 22
 OrderDiscount = get_model('order', 'OrderDiscount')
23 23
 Benefit = get_model('offer', 'Benefit')
24
-MetaDataForm, ConditionForm, BenefitForm, RestrictionsForm, OfferSearchForm = get_classes(
25
-    'dashboard.offers.forms', [
26
-        'MetaDataForm', 'ConditionForm', 'BenefitForm', 'RestrictionsForm',
27
-        'OfferSearchForm'])
24
+MetaDataForm, ConditionForm, BenefitForm, RestrictionsForm, OfferSearchForm \
25
+    = get_classes('dashboard.offers.forms',
26
+                  ['MetaDataForm', 'ConditionForm', 'BenefitForm',
27
+                   'RestrictionsForm', 'OfferSearchForm'])
28 28
 OrderDiscountCSVFormatter = get_class(
29 29
     'dashboard.offers.reports', 'OrderDiscountCSVFormatter')
30 30
 
@@ -40,7 +40,7 @@ class OfferListView(ListView):
40 40
             offer_type=ConditionalOffer.SITE)
41 41
         qs = sort_queryset(qs, self.request,
42 42
                            ['name', 'start_date', 'end_date',
43
-                           'num_applications', 'total_discount'])
43
+                            'num_applications', 'total_discount'])
44 44
 
45 45
         self.description = _("All offers")
46 46
 
@@ -91,7 +91,8 @@ class OfferWizardStepView(FormView):
91 91
                 request, _("%s step not complete") % (
92 92
                     self.previous_view.step_name.title(),))
93 93
             return HttpResponseRedirect(self.get_back_url())
94
-        return super(OfferWizardStepView, self).dispatch(request, *args, **kwargs)
94
+        return super(OfferWizardStepView, self).dispatch(request, *args,
95
+                                                         **kwargs)
95 96
 
96 97
     def is_previous_step_complete(self, request):
97 98
         if not self.previous_view:
@@ -153,8 +154,8 @@ class OfferWizardStepView(FormView):
153 154
         json_qs = session_data.get(self._key(step_name, is_object=True), None)
154 155
         if json_qs:
155 156
             # Recreate model instance from passed data
156
-            deserialised_obj = list(serializers.deserialize('json', json_qs))[0]
157
-            return deserialised_obj.object
157
+            deserialised_obj = list(serializers.deserialize('json', json_qs))
158
+            return deserialised_obj[0].object
158 159
 
159 160
     def _fetch_session_offer(self):
160 161
         """

+ 12
- 10
oscar/apps/dashboard/orders/app.py Datei anzeigen

@@ -8,11 +8,11 @@ class OrdersDashboardApplication(Application):
8 8
     name = None
9 9
     default_permissions = ['is_staff', ]
10 10
     permissions_map = {
11
-        'order-list':             (['is_staff'], ['partner.dashboard_access']),
12
-        'order-stats':            (['is_staff'], ['partner.dashboard_access']),
13
-        'order-detail':           (['is_staff'], ['partner.dashboard_access']),
14
-        'order-detail-note':      (['is_staff'], ['partner.dashboard_access']),
15
-        'order-line-detail':      (['is_staff'], ['partner.dashboard_access']),
11
+        'order-list': (['is_staff'], ['partner.dashboard_access']),
12
+        'order-stats': (['is_staff'], ['partner.dashboard_access']),
13
+        'order-detail': (['is_staff'], ['partner.dashboard_access']),
14
+        'order-detail-note': (['is_staff'], ['partner.dashboard_access']),
15
+        'order-line-detail': (['is_staff'], ['partner.dashboard_access']),
16 16
         'order-shipping-address': (['is_staff'], ['partner.dashboard_access']),
17 17
     }
18 18
 
@@ -23,9 +23,10 @@ class OrdersDashboardApplication(Application):
23 23
     order_stats_view = views.OrderStatsView
24 24
 
25 25
     def get_urls(self):
26
-        urlpatterns = patterns('',
26
+        urls = [
27 27
             url(r'^$', self.order_list_view.as_view(), name='order-list'),
28
-            url(r'^statistics/$', self.order_stats_view.as_view(), name='order-stats'),
28
+            url(r'^statistics/$', self.order_stats_view.as_view(),
29
+                name='order-stats'),
29 30
             url(r'^(?P<number>[-\w]+)/$',
30 31
                 self.order_detail_view.as_view(), name='order-detail'),
31 32
             url(r'^(?P<number>[-\w]+)/notes/(?P<note_id>\d+)/$',
@@ -33,9 +34,10 @@ class OrdersDashboardApplication(Application):
33 34
             url(r'^(?P<number>[-\w]+)/lines/(?P<line_id>\d+)/$',
34 35
                 self.line_detail_view.as_view(), name='order-line-detail'),
35 36
             url(r'^(?P<number>[-\w]+)/shipping-address/$',
36
-                self.shipping_address_view.as_view(), name='order-shipping-address'),
37
-        )
38
-        return self.post_process_urls(urlpatterns)
37
+                self.shipping_address_view.as_view(),
38
+                name='order-shipping-address'),
39
+        ]
40
+        return self.post_process_urls(patterns('', *urls))
39 41
 
40 42
 
41 43
 application = OrdersDashboardApplication()

+ 21
- 15
oscar/apps/dashboard/orders/forms.py Datei anzeigen

@@ -29,12 +29,12 @@ class OrderStatsForm(forms.Form):
29 29
         date_from = self.cleaned_data['date_from']
30 30
         date_to = self.cleaned_data['date_to']
31 31
         if date_from and date_to:
32
-            # We want to include end date so we adjust the date we use with the 'range'
33
-            # function.
34
-            self._filters = {'date_placed__range': [date_from,
35
-                                                    date_to +
36
-                                                    datetime.timedelta(days=1)]}
37
-            self._description = _('Orders placed between %(date_from)s and %(date_to)s') % {
32
+            # We want to include end date so we adjust the date we use with the
33
+            # 'range' function.
34
+            self._filters = {'date_placed__range':
35
+                             [date_from, date_to + datetime.timedelta(days=1)]}
36
+            self._description = _('Orders placed between %(date_from)s and'
37
+                                  ' %(date_to)s') % {
38 38
                 'date_from': date_from,
39 39
                 'date_to': date_to}
40 40
         elif date_from and not date_to:
@@ -65,8 +65,11 @@ class OrderSearchForm(forms.Form):
65 65
     upc = forms.CharField(required=False, label=_("UPC"))
66 66
     partner_sku = forms.CharField(required=False, label=_("Partner SKU"))
67 67
 
68
-    status_choices = (('', '---------'),) + tuple([(v, v) for v in Order.all_statuses()])
69
-    status = forms.ChoiceField(choices=status_choices, label=_("Status"), required=False)
68
+    status_choices = (('', '---------'),) + tuple([(v, v)
69
+                                                   for v
70
+                                                   in Order.all_statuses()])
71
+    status = forms.ChoiceField(choices=status_choices, label=_("Status"),
72
+                               required=False)
70 73
 
71 74
     date_from = forms.DateField(required=False, label=_("Date from"))
72 75
     date_to = forms.DateField(required=False, label=_("Date to"))
@@ -79,8 +82,10 @@ class OrderSearchForm(forms.Form):
79 82
 
80 83
     format_choices = (('html', _('HTML')),
81 84
                       ('csv', _('CSV')),)
82
-    response_format = forms.ChoiceField(widget=forms.RadioSelect, required=False,
83
-        choices=format_choices, initial='html', label=_("Get results as"))
85
+    response_format = forms.ChoiceField(widget=forms.RadioSelect,
86
+                                        required=False, choices=format_choices,
87
+                                        initial='html',
88
+                                        label=_("Get results as"))
84 89
 
85 90
     def __init__(self, *args, **kwargs):
86 91
         # ensure that 'response_format' is always set
@@ -93,11 +98,12 @@ class OrderSearchForm(forms.Form):
93 98
         else:
94 99
             data = None
95 100
 
96
-        if data and data.get('response_format', None) not in self.format_choices:
97
-            # handle POST/GET dictionaries, whose are unmutable
98
-            if isinstance(data, QueryDict):
99
-                data = data.dict()
100
-            data['response_format'] = 'html'
101
+        if data:
102
+            if data.get('response_format', None) not in self.format_choices:
103
+                # handle POST/GET dictionaries, whose are unmutable
104
+                if isinstance(data, QueryDict):
105
+                    data = data.dict()
106
+                data['response_format'] = 'html'
101 107
 
102 108
         super(OrderSearchForm, self).__init__(data, *args, **kwargs)
103 109
         self.fields['payment_method'].choices = self.payment_method_choices()

+ 98
- 61
oscar/apps/dashboard/orders/views.py Datei anzeigen

@@ -107,7 +107,8 @@ class OrderListView(BulkEditMixin, ListView):
107 107
     form_class = forms.OrderSearchForm
108 108
     desc_template = _("%(main_filter)s %(name_filter)s %(title_filter)s"
109 109
                       "%(upc_filter)s %(sku_filter)s %(date_filter)s"
110
-                      "%(voucher_filter)s %(payment_filter)s %(status_filter)s")
110
+                      "%(voucher_filter)s %(payment_filter)s"
111
+                      "%(status_filter)s")
111 112
     paginate_by = 25
112 113
     description = ''
113 114
     actions = ('download_selected_orders',)
@@ -158,37 +159,48 @@ class OrderListView(BulkEditMixin, ListView):
158 159
             return desc_ctx
159 160
 
160 161
         if data['order_number']:
161
-            desc_ctx['main_filter'] = _('Orders with number starting with "%s"') % data['order_number']
162
+            desc_ctx['main_filter'] = _('Orders with number starting with'
163
+                                        ' "%(order_number)s"') % data
162 164
 
163 165
         if data['name']:
164
-            desc_ctx['name_filter'] = _(" with customer name matching '%s'") % data['name']
166
+            desc_ctx['name_filter'] = _(" with customer name matching"
167
+                                        " '%(name)s'") % data
165 168
 
166 169
         if data['product_title']:
167
-            desc_ctx['title_filter'] = _(" including an item with title matching '%s'") % data['product_title']
170
+            desc_ctx['title_filter'] \
171
+                = _(" including an item with title matching"
172
+                    " '%(product_title)s'") % data
168 173
 
169 174
         if data['upc']:
170
-            desc_ctx['upc_filter'] = _(" including an item with UPC '%s'") % data['upc']
175
+            desc_ctx['upc_filter'] = _(" including an item with UPC"
176
+                                       " '%(upc)s'") % data
171 177
 
172 178
         if data['partner_sku']:
173
-            desc_ctx['upc_filter'] = _(" including an item with ID '%s'") % data['partner_sku']
179
+            desc_ctx['upc_filter'] = _(" including an item with ID"
180
+                                       " '%(partner_sku)s'") % data
174 181
 
175 182
         if data['date_from'] and data['date_to']:
176
-            desc_ctx['date_filter'] = _(" placed between %(start_date)s and %(end_date)s") % {
177
-                'start_date': format_datetime(data['date_from']),
178
-                'end_date': format_datetime(data['date_to'])}
183
+            desc_ctx['date_filter'] \
184
+                = _(" placed between %(start_date)s and %(end_date)s") \
185
+                % {'start_date': format_datetime(data['date_from']),
186
+                   'end_date': format_datetime(data['date_to'])}
179 187
         elif data['date_from']:
180
-            desc_ctx['date_filter'] = _(" placed since %s") % format_datetime(data['date_from'])
188
+            desc_ctx['date_filter'] = _(" placed since %s") \
189
+                % format_datetime(data['date_from'])
181 190
         elif data['date_to']:
182 191
             date_to = data['date_to'] + datetime.timedelta(days=1)
183
-            desc_ctx['date_filter'] = _(" placed before %s") % format_datetime(date_to)
192
+            desc_ctx['date_filter'] = _(" placed before %s") \
193
+                % format_datetime(date_to)
184 194
         if data['voucher']:
185
-            desc_ctx['voucher_filter'] = _(" using voucher '%s'") % data['voucher']
195
+            desc_ctx['voucher_filter'] = _(" using voucher '%(voucher)s'") \
196
+                % data
186 197
 
187 198
         if data['payment_method']:
188
-            desc_ctx['payment_filter'] = _(" paid for by %s") % data['payment_method']
199
+            desc_ctx['payment_filter'] = _(" paid for by %(payment_method)s") \
200
+                % data
189 201
 
190 202
         if data['status']:
191
-            desc_ctx['status_filter'] = _(" with status %s") % data['status']
203
+            desc_ctx['status_filter'] = _(" with status %(status)s") % data
192 204
 
193 205
         return desc_ctx
194 206
 
@@ -224,7 +236,8 @@ class OrderListView(BulkEditMixin, ListView):
224 236
                 number__istartswith=data['order_number'])
225 237
 
226 238
         if data['name']:
227
-            # If the value is two words, then assume they are first name and last name
239
+            # If the value is two words, then assume they are first name and
240
+            # last name
228 241
             parts = data['name'].split()
229 242
             allow_anon = getattr(settings, 'OSCAR_ALLOW_ANON_CHECKOUT', False)
230 243
 
@@ -233,18 +246,19 @@ class OrderListView(BulkEditMixin, ListView):
233 246
             else:
234 247
                 parts = [parts[0], parts[1:]]
235 248
 
236
-            filter = Q(user__first_name__istartswith=parts[0]) |\
237
-                     Q(user__last_name__istartswith=parts[1])
249
+            filter = Q(user__first_name__istartswith=parts[0])
250
+            filter |= Q(user__last_name__istartswith=parts[1])
238 251
             if allow_anon:
239
-                filter |= Q(billing_address__first_name__istartswith=parts[0]) |\
240
-                          Q(shipping_address__first_name__istartswith=parts[0]) |\
241
-                          Q(billing_address__last_name__istartswith=parts[1]) |\
242
-                          Q(shipping_address__last_name__istartswith=parts[1])
252
+                filter |= Q(billing_address__first_name__istartswith=parts[0])
253
+                filter |= Q(shipping_address__first_name__istartswith=parts[0])
254
+                filter |= Q(billing_address__last_name__istartswith=parts[1])
255
+                filter |= Q(shipping_address__last_name__istartswith=parts[1])
243 256
 
244 257
             queryset = queryset.filter(filter).distinct()
245 258
 
246 259
         if data['product_title']:
247
-            queryset = queryset.filter(lines__title__istartswith=data['product_title']).distinct()
260
+            queryset = queryset.filter(
261
+                lines__title__istartswith=data['product_title']).distinct()
248 262
 
249 263
         if data['upc']:
250 264
             queryset = queryset.filter(lines__upc=data['upc'])
@@ -255,7 +269,8 @@ class OrderListView(BulkEditMixin, ListView):
255 269
         if data['date_from'] and data['date_to']:
256 270
             # Add 24 hours to make search inclusive
257 271
             date_to = data['date_to'] + datetime.timedelta(days=1)
258
-            queryset = queryset.filter(date_placed__gte=data['date_from']).filter(date_placed__lt=date_to)
272
+            queryset = queryset.filter(date_placed__gte=data['date_from'])
273
+            queryset = queryset.filter(date_placed__lt=date_to)
259 274
         elif data['date_from']:
260 275
             queryset = queryset.filter(date_placed__gte=data['date_from'])
261 276
         elif data['date_to']:
@@ -263,10 +278,12 @@ class OrderListView(BulkEditMixin, ListView):
263 278
             queryset = queryset.filter(date_placed__lt=date_to)
264 279
 
265 280
         if data['voucher']:
266
-            queryset = queryset.filter(discounts__voucher_code=data['voucher']).distinct()
281
+            queryset = queryset.filter(
282
+                discounts__voucher_code=data['voucher']).distinct()
267 283
 
268 284
         if data['payment_method']:
269
-            queryset = queryset.filter(sources__source_type__code=data['payment_method']).distinct()
285
+            queryset = queryset.filter(
286
+                sources__source_type__code=data['payment_method']).distinct()
270 287
 
271 288
         if data['status']:
272 289
             queryset = queryset.filter(status=data['status'])
@@ -299,7 +316,8 @@ class OrderListView(BulkEditMixin, ListView):
299 316
 
300 317
     def download_selected_orders(self, request, orders):
301 318
         response = HttpResponse(content_type='text/csv')
302
-        response['Content-Disposition'] = 'attachment; filename=%s' % self.get_download_filename(request)
319
+        response['Content-Disposition'] = 'attachment; filename=%s' \
320
+            % self.get_download_filename(request)
303 321
         writer = CsvUnicodeWriter(response, delimiter=',')
304 322
 
305 323
         meta_data = (('number', _('Order number')),
@@ -333,7 +351,8 @@ class OrderListView(BulkEditMixin, ListView):
333 351
             else:
334 352
                 row['billing_address_name'] = ''
335 353
 
336
-            encoded_values = [unicode(value).encode('utf8') for value in row.values()]
354
+            encoded_values = [unicode(value).encode('utf8')
355
+                              for value in row.values()]
337 356
             writer.writerow(encoded_values)
338 357
         return response
339 358
 
@@ -408,15 +427,18 @@ class OrderDetailView(DetailView):
408 427
                     line_quantities.append(int(qty))
409 428
                 lines = order.lines.filter(id__in=line_ids)
410 429
                 if not lines.exists():
411
-                    messages.error(self.request, _("You must select some lines to act on"))
430
+                    messages.error(self.request,
431
+                                   _("You must select some lines to act on"))
412 432
                     return self.reload_page_response()
413
-                return getattr(self, line_action)(request, order, lines, line_quantities)
433
+                return getattr(self, line_action)(request, order, lines,
434
+                                                  line_quantities)
414 435
 
415 436
         messages.error(request, _("No valid action submitted"))
416 437
         return self.reload_page_response()
417 438
 
418 439
     def reload_page_response(self, fragment=None):
419
-        url = reverse('dashboard:order-detail', kwargs={'number': self.object.number})
440
+        url = reverse('dashboard:order-detail', kwargs={'number':
441
+                                                        self.object.number})
420 442
         if fragment:
421 443
             url += '#' + fragment
422 444
         return HttpResponseRedirect(url)
@@ -447,47 +469,51 @@ class OrderDetailView(DetailView):
447 469
     def change_order_status(self, request, order):
448 470
         new_status = request.POST['new_status'].strip()
449 471
         if not new_status:
450
-            messages.error(request, _("The new status '%s' is not valid") % new_status)
472
+            messages.error(request, _("The new status '%s' is not valid")
473
+                           % new_status)
451 474
             return self.reload_page_response()
452 475
         if not new_status in order.available_statuses():
453
-            messages.error(request, _("The new status '%s' is not valid for this order") % new_status)
476
+            messages.error(request, _("The new status '%s' is not valid for"
477
+                                      " this order") % new_status)
454 478
             return self.reload_page_response()
455 479
 
456 480
         handler = EventHandler(request.user)
457 481
         try:
458 482
             handler.handle_order_status_change(order, new_status)
459 483
         except PaymentError, e:
460
-            messages.error(request, _("Unable to change order status due to payment error: %s") % e)
484
+            messages.error(request, _("Unable to change order status due to"
485
+                                      " payment error: %s") % e)
461 486
         else:
462
-            msg = _("Order status changed from '%(old_status)s' to '%(new_status)s'") % {
463
-                'old_status': order.status,
464
-                'new_status': new_status}
487
+            msg = _("Order status changed from '%(old_status)s' to"
488
+                    " '%(new_status)s'") % {'old_status': order.status,
489
+                                            'new_status': new_status}
465 490
             messages.info(request, msg)
466 491
             order.notes.create(user=request.user, message=msg,
467
-                            note_type=OrderNote.SYSTEM)
492
+                               note_type=OrderNote.SYSTEM)
468 493
         return self.reload_page_response(fragment='activity')
469 494
 
470 495
     def change_line_statuses(self, request, order, lines, quantities):
471 496
         new_status = request.POST['new_status'].strip()
472 497
         if not new_status:
473
-            messages.error(request, _("The new status '%s' is not valid") % new_status)
498
+            messages.error(request, _("The new status '%s' is not valid")
499
+                           % new_status)
474 500
             return self.reload_page_response()
475 501
         errors = []
476 502
         for line in lines:
477 503
             if new_status not in line.available_statuses():
478
-                errors.append(_("'%(status)s' is not a valid new status for line %(line_id)d") % {
479
-                    'status': new_status,
480
-                    'line_id': line.id})
504
+                errors.append(_("'%(status)s' is not a valid new status for"
505
+                                " line %(line_id)d") % {'status': new_status,
506
+                                                        'line_id': line.id})
481 507
         if errors:
482 508
             messages.error(request, "\n".join(errors))
483 509
             return self.reload_page_response()
484 510
 
485 511
         msgs = []
486 512
         for line in lines:
487
-            msg = _("Status of line #%(line_id)d changed from '%(old_status)s' to '%(new_status)s'") % {
488
-                        'line_id': line.id,
489
-                        'old_status': line.status,
490
-                        'new_status': new_status}
513
+            msg = _("Status of line #%(line_id)d changed from '%(old_status)s'"
514
+                    " to '%(new_status)s'") % {'line_id': line.id,
515
+                                               'old_status': line.status,
516
+                                               'new_status': new_status}
491 517
             msgs.append(msg)
492 518
             line.set_status(new_status)
493 519
         message = "\n".join(msgs)
@@ -501,7 +527,8 @@ class OrderDetailView(DetailView):
501 527
         try:
502 528
             event_type = ShippingEventType._default_manager.get(code=code)
503 529
         except ShippingEventType.DoesNotExist:
504
-            messages.error(request, _("The event type '%s' is not valid") % code)
530
+            messages.error(request, _("The event type '%s' is not valid")
531
+                           % code)
505 532
             return self.reload_page_response()
506 533
 
507 534
         reference = request.POST.get('reference', None)
@@ -510,11 +537,14 @@ class OrderDetailView(DetailView):
510 537
                                                  quantities,
511 538
                                                  reference=reference)
512 539
         except InvalidShippingEvent, e:
513
-            messages.error(request, _("Unable to create shipping event: %s") % e)
540
+            messages.error(request,
541
+                           _("Unable to create shipping event: %s") % e)
514 542
         except InvalidStatus, e:
515
-            messages.error(request, _("Unable to create shipping event: %s") % e)
543
+            messages.error(request,
544
+                           _("Unable to create shipping event: %s") % e)
516 545
         except PaymentError, e:
517
-            messages.error(request, _("Unable to create shipping event due to payment error: %s") % e)
546
+            messages.error(request, _("Unable to create shipping event due to"
547
+                                      " payment error: %s") % e)
518 548
         else:
519 549
             messages.success(request, _("Shipping event created"))
520 550
         return self.reload_page_response()
@@ -534,13 +564,15 @@ class OrderDetailView(DetailView):
534 564
         try:
535 565
             event_type = PaymentEventType._default_manager.get(code=code)
536 566
         except PaymentEventType.DoesNotExist:
537
-            messages.error(request, _("The event type '%s' is not valid") % code)
567
+            messages.error(request, _("The event type '%s' is not valid")
568
+                           % code)
538 569
             return self.reload_page_response()
539 570
         try:
540 571
             EventHandler().handle_payment_event(order, event_type, amount,
541 572
                                                 lines, quantities)
542 573
         except PaymentError, e:
543
-            messages.error(request, _("Unable to change order status due to payment error: %s") % e)
574
+            messages.error(request, _("Unable to change order status due to"
575
+                                      " payment error: %s") % e)
544 576
         else:
545 577
             messages.info(request, _("Payment event created"))
546 578
         return self.reload_page_response()
@@ -595,11 +627,14 @@ def get_changes_between_models(model1, model2, excludes=None):
595 627
         excludes = []
596 628
     changes = {}
597 629
     for field in model1._meta.fields:
598
-        if not (isinstance(field, (fields.AutoField, fields.related.RelatedField))
630
+        if (isinstance(field, (fields.AutoField,
631
+                               fields.related.RelatedField))
599 632
                 or field.name in excludes):
600
-            if field.value_from_object(model1) != field.value_from_object(model2):
601
-                changes[field.verbose_name] = (field.value_from_object(model1),
602
-                                               field.value_from_object(model2))
633
+            continue
634
+
635
+        if field.value_from_object(model1) != field.value_from_object(model2):
636
+            changes[field.verbose_name] = (field.value_from_object(model1),
637
+                                           field.value_from_object(model2))
603 638
     return changes
604 639
 
605 640
 
@@ -610,10 +645,11 @@ def get_change_summary(model1, model2):
610 645
     changes = get_changes_between_models(model1, model2, ['search_text'])
611 646
     change_descriptions = []
612 647
     for field, delta in changes.items():
613
-        change_descriptions.append(_("%(field)s changed from '%(old_value)s' to '%(new_value)s'") % {
614
-            'field': field,
615
-            'old_value': delta[0],
616
-            'new_value': delta[1]})
648
+        change_descriptions.append(_("%(field)s changed from '%(old_value)s'"
649
+                                     " to '%(new_value)s'")
650
+                                   % {'field': field,
651
+                                      'old_value': delta[0],
652
+                                      'new_value': delta[1]})
617 653
     return "\n".join(change_descriptions)
618 654
 
619 655
 
@@ -644,9 +680,10 @@ class ShippingAddressUpdateView(UpdateView):
644 680
         if changes:
645 681
             msg = _("Delivery address updated:\n%s") % changes
646 682
             self.object.order.notes.create(user=self.request.user, message=msg,
647
-                                        note_type=OrderNote.SYSTEM)
683
+                                           note_type=OrderNote.SYSTEM)
648 684
         return response
649 685
 
650 686
     def get_success_url(self):
651 687
         messages.info(self.request, _("Delivery address updated"))
652
-        return reverse('dashboard:order-detail', kwargs={'number': self.object.order.number, })
688
+        return reverse('dashboard:order-detail',
689
+                       kwargs={'number': self.object.order.number, })

+ 3
- 3
oscar/apps/dashboard/pages/app.py Datei anzeigen

@@ -17,15 +17,15 @@ class FlatPageManagementApplication(Application):
17 17
         """
18 18
         Get URL patterns defined for flatpage management application.
19 19
         """
20
-        urlpatterns = patterns('',
20
+        urls = [
21 21
             url(r'^$', self.list_view.as_view(), name='page-list'),
22 22
             url(r'^create/$', self.create_view.as_view(), name='page-create'),
23 23
             url(r'^update/(?P<pk>[-\w]+)/$',
24 24
                 self.update_view.as_view(), name='page-update'),
25 25
             url(r'^delete/(?P<pk>\d+)/$',
26 26
                 self.delete_view.as_view(), name='page-delete')
27
-        )
28
-        return self.post_process_urls(urlpatterns)
27
+        ]
28
+        return self.post_process_urls(patterns('', *urls))
29 29
 
30 30
 
31 31
 application = FlatPageManagementApplication()

+ 2
- 1
oscar/apps/dashboard/pages/views.py Datei anzeigen

@@ -49,7 +49,8 @@ class PageListView(ListView):
49 49
 
50 50
         if data['title']:
51 51
             queryset = queryset.filter(title__icontains=data['title'])
52
-            self.desc_ctx['title_filter'] = _(" with title containing '%s'") % data['title']
52
+            self.desc_ctx['title_filter'] \
53
+                = _(" with title containing '%s'") % data['title']
53 54
 
54 55
         return queryset
55 56
 

+ 3
- 3
oscar/apps/dashboard/partners/app.py Datei anzeigen

@@ -20,7 +20,7 @@ class PartnersDashboardApplication(Application):
20 20
     user_update_view = views.PartnerUserUpdateView
21 21
 
22 22
     def get_urls(self):
23
-        urlpatterns = patterns('',
23
+        urls = [
24 24
             url(r'^$', self.list_view.as_view(), name='partner-list'),
25 25
             url(r'^create/$', self.create_view.as_view(),
26 26
                 name='partner-create'),
@@ -42,8 +42,8 @@ class PartnersDashboardApplication(Application):
42 42
             url(r'^(?P<partner_pk>\d+)/users/(?P<user_pk>\d+)/update/$',
43 43
                 self.user_update_view.as_view(),
44 44
                 name='partner-user-update'),
45
-        )
46
-        return self.post_process_urls(urlpatterns)
45
+        ]
46
+        return self.post_process_urls(patterns('', *urls))
47 47
 
48 48
 
49 49
 application = PartnersDashboardApplication()

+ 2
- 1
oscar/apps/dashboard/partners/forms.py Datei anzeigen

@@ -4,7 +4,8 @@ from django.core import validators
4 4
 from django.db.models import get_model
5 5
 from django.utils.translation import ugettext_lazy as _
6 6
 
7
-from oscar.apps.customer.forms import EmailUserCreationForm, CommonPasswordValidator
7
+from oscar.apps.customer.forms import (EmailUserCreationForm,
8
+                                       CommonPasswordValidator)
8 9
 from oscar.core.compat import get_user_model
9 10
 
10 11
 User = get_user_model()

+ 10
- 7
oscar/apps/dashboard/partners/views.py Datei anzeigen

@@ -9,7 +9,8 @@ from django.template.loader import render_to_string
9 9
 from django.views import generic
10 10
 
11 11
 from oscar.apps.customer.utils import normalise_email
12
-from oscar.apps.dashboard.partners.forms import UserEmailForm, ExistingUserForm, NewUserForm
12
+from oscar.apps.dashboard.partners.forms import (UserEmailForm,
13
+                                                 ExistingUserForm, NewUserForm)
13 14
 from oscar.core.loading import get_classes
14 15
 from oscar.core.compat import get_user_model
15 16
 from oscar.views import sort_queryset
@@ -237,13 +238,14 @@ class PartnerUserLinkView(generic.View):
237 238
         partner = get_object_or_404(Partner, pk=partner_pk)
238 239
         if self.link_user(user, partner):
239 240
             messages.success(
240
-                request, _("User '%(name)s' was linked to '%(partner_name)s'") %
241
-                         {'name': name, 'partner_name': partner.name})
241
+                request,
242
+                _("User '%(name)s' was linked to '%(partner_name)s'")
243
+                % {'name': name, 'partner_name': partner.name})
242 244
         else:
243 245
             messages.info(
244 246
                 request,
245
-                _("User '%(name)s' is already linked to '%(partner_name)s'") %
246
-                    {'name': name, 'partner_name': partner.name})
247
+                _("User '%(name)s' is already linked to '%(partner_name)s'")
248
+                % {'name': name, 'partner_name': partner.name})
247 249
         return HttpResponseRedirect(reverse('dashboard:partner-manage',
248 250
                                             kwargs={'pk': partner_pk}))
249 251
 
@@ -255,7 +257,8 @@ class PartnerUserUnlinkView(generic.View):
255 257
         Unlinks a user from a partner, and removes the dashboard permission
256 258
         if she's not linked to any other partners.
257 259
 
258
-        Returns False if the user was not linked to the partner; True otherwise.
260
+        Returns False if the user was not linked to the partner; True
261
+        otherwise.
259 262
         """
260 263
         if not partner.users.filter(pk=user.pk).exists():
261 264
             return False
@@ -282,7 +285,7 @@ class PartnerUserUnlinkView(generic.View):
282 285
             messages.error(
283 286
                 request,
284 287
                 _("User '%(name)s' is not linked to '%(partner_name)s'") %
285
-                    {'name': name, 'partner_name': partner.name})
288
+                {'name': name, 'partner_name': partner.name})
286 289
         return HttpResponseRedirect(reverse('dashboard:partner-manage',
287 290
                                             kwargs={'pk': partner_pk}))
288 291
 

+ 11
- 11
oscar/apps/dashboard/promotions/app.py Datei anzeigen

@@ -16,15 +16,15 @@ class PromotionsDashboardApplication(Application):
16 16
     delete_page_promotion_view = views.DeletePagePromotionView
17 17
 
18 18
     for klass in PROMOTION_CLASSES:
19
-        locals()['create_%s_view' % klass.classname()] = \
20
-                getattr(views, 'Create%sView' % klass.__name__)
21
-        locals()['update_%s_view' % klass.classname()] = \
22
-                getattr(views, 'Update%sView' % klass.__name__)
23
-        locals()['delete_%s_view' % klass.classname()] = \
24
-                getattr(views, 'Delete%sView' % klass.__name__)
19
+        locals()['create_%s_view' % klass.classname()] \
20
+            = getattr(views, 'Create%sView' % klass.__name__)
21
+        locals()['update_%s_view' % klass.classname()] \
22
+            = getattr(views, 'Update%sView' % klass.__name__)
23
+        locals()['delete_%s_view' % klass.classname()] \
24
+            = getattr(views, 'Delete%sView' % klass.__name__)
25 25
 
26 26
     def get_urls(self):
27
-        urlpatterns = patterns('',
27
+        urls = [
28 28
             url(r'^$', self.list_view.as_view(), name='promotion-list'),
29 29
             url(r'^pages/$', self.page_list.as_view(),
30 30
                 name='promotion-list-by-page'),
@@ -35,11 +35,11 @@ class PromotionsDashboardApplication(Application):
35 35
                 name='promotion-create-redirect'),
36 36
             url(r'^page-promotion/(?P<pk>\d+)/$',
37 37
                 self.delete_page_promotion_view.as_view(),
38
-                name='pagepromotion-delete'))
38
+                name='pagepromotion-delete')]
39 39
 
40 40
         for klass in PROMOTION_CLASSES:
41 41
             code = klass.classname()
42
-            urlpatterns += patterns('',
42
+            urls += [
43 43
                 url(r'create/%s/' % code,
44 44
                     getattr(self, 'create_%s_view' % code).as_view(),
45 45
                     name='promotion-create-%s' % code),
@@ -48,9 +48,9 @@ class PromotionsDashboardApplication(Application):
48 48
                     name='promotion-update'),
49 49
                 url(r'^delete/(?P<ptype>%s)/(?P<pk>\d+)/$' % code,
50 50
                     getattr(self, 'delete_%s_view' % code).as_view(),
51
-                    name='promotion-delete'))
51
+                    name='promotion-delete')]
52 52
 
53
-        return self.post_process_urls(urlpatterns)
53
+        return self.post_process_urls(patterns('', *urls))
54 54
 
55 55
 
56 56
 application = PromotionsDashboardApplication()

+ 5
- 9
oscar/apps/dashboard/promotions/forms.py Datei anzeigen

@@ -7,10 +7,10 @@ from oscar.apps.promotions.conf import PROMOTION_CLASSES
7 7
 from oscar.forms.fields import ExtendedURLField
8 8
 from oscar.core.loading import get_classes, get_class
9 9
 
10
-HandPickedProductList, RawHTML, SingleProduct, PagePromotion, OrderedProduct = get_classes(
11
-    'promotions.models',
12
-    ['HandPickedProductList', 'RawHTML', 'SingleProduct', 'PagePromotion',
13
-     'OrderedProduct'])
10
+HandPickedProductList, RawHTML, SingleProduct, PagePromotion, OrderedProduct \
11
+    = get_classes('promotions.models',
12
+                  ['HandPickedProductList', 'RawHTML', 'SingleProduct',
13
+                   'PagePromotion', 'OrderedProduct'])
14 14
 ProductSelect = get_class('dashboard.catalogue.widgets', 'ProductSelect')
15 15
 
16 16
 
@@ -31,9 +31,7 @@ class RawHTMLForm(forms.ModelForm):
31 31
 class SingleProductForm(forms.ModelForm):
32 32
     class Meta:
33 33
         model = SingleProduct
34
-        widgets = {
35
-            'product': ProductSelect,
36
-            }
34
+        widgets = {'product': ProductSelect}
37 35
 
38 36
 
39 37
 class HandPickedProductListForm(forms.ModelForm):
@@ -78,5 +76,3 @@ class PagePromotionForm(forms.ModelForm):
78 76
             page_url += '/'
79 77
 
80 78
         return page_url
81
-
82
-

+ 29
- 21
oscar/apps/dashboard/promotions/views.py Datei anzeigen

@@ -13,16 +13,18 @@ from django.shortcuts import HttpResponse
13 13
 from oscar.core.loading import get_classes
14 14
 from oscar.apps.promotions.conf import PROMOTION_CLASSES
15 15
 
16
-SingleProduct, RawHTML, Image, MultiImage, \
17
-    AutomaticProductList, PagePromotion, \
18
-    HandPickedProductList = get_classes('promotions.models',
19
-    ['SingleProduct', 'RawHTML', 'Image', 'MultiImage', 'AutomaticProductList',
20
-     'PagePromotion', 'HandPickedProductList'])
16
+SingleProduct, RawHTML, Image, MultiImage, AutomaticProductList, \
17
+    PagePromotion, HandPickedProductList \
18
+    = get_classes('promotions.models',
19
+                  ['SingleProduct', 'RawHTML', 'Image', 'MultiImage',
20
+                   'AutomaticProductList', 'PagePromotion',
21
+                   'HandPickedProductList'])
21 22
 SelectForm, RawHTMLForm, PagePromotionForm, HandPickedProductListForm, \
22
-    SingleProductForm, OrderedProductFormSet = get_classes(
23
-    'dashboard.promotions.forms',
24
-    ['PromotionTypeSelectForm', 'RawHTMLForm', 'PagePromotionForm',
25
-     'HandPickedProductListForm', 'SingleProductForm', 'OrderedProductFormSet'])
23
+    SingleProductForm, OrderedProductFormSet \
24
+    = get_classes('dashboard.promotions.forms',
25
+                  ['PromotionTypeSelectForm', 'RawHTMLForm',
26
+                   'PagePromotionForm', 'HandPickedProductListForm',
27
+                   'SingleProductForm', 'OrderedProductFormSet'])
26 28
 
27 29
 
28 30
 class ListView(generic.TemplateView):
@@ -80,12 +82,11 @@ class PageDetailView(generic.TemplateView):
80 82
         for code, name in settings.OSCAR_PROMOTION_POSITIONS:
81 83
             promotions = PagePromotion._default_manager.select_related() \
82 84
                                                        .filter(page_url=path,
83
-                                                               position=code) \
84
-                                                       .order_by('display_order')
85
+                                                               position=code)
85 86
             ctx.append({
86 87
                 'code': code,
87 88
                 'name': name,
88
-                'promotions': promotions,
89
+                'promotions': promotions.order_by('display_order'),
89 90
             })
90 91
         return ctx
91 92
 
@@ -181,7 +182,8 @@ class CreateHandPickedProductListView(CreateView):
181 182
         ctx = super(CreateHandPickedProductListView,
182 183
                     self).get_context_data(**kwargs)
183 184
         if 'product_formset' not in kwargs:
184
-            ctx['product_formset'] = OrderedProductFormSet(instance=self.object)
185
+            ctx['product_formset'] \
186
+                = OrderedProductFormSet(instance=self.object)
185 187
         return ctx
186 188
 
187 189
     def form_valid(self, form):
@@ -192,7 +194,8 @@ class CreateHandPickedProductListView(CreateView):
192 194
             promotion.save()
193 195
             product_formset.save()
194 196
             self.object = promotion
195
-            messages.success(self.request, _('Product list content block created'))
197
+            messages.success(self.request,
198
+                             _('Product list content block created'))
196 199
             return HttpResponseRedirect(self.get_success_url())
197 200
 
198 201
         ctx = self.get_context_data(product_formset=product_formset)
@@ -235,10 +238,12 @@ class UpdateView(PromotionMixin, generic.UpdateView):
235 238
         if form.is_valid():
236 239
             form.save()
237 240
             page_url = form.cleaned_data['page_url']
238
-            messages.success(request, _("Content block '%(block)s' added to page '%(page)s'") % {
239
-                'block': promotion.name,
240
-                'page': page_url})
241
-            return HttpResponseRedirect(reverse('dashboard:promotion-update', kwargs=kwargs))
241
+            messages.success(request, _("Content block '%(block)s' added to"
242
+                                        " page '%(page)s'")
243
+                             % {'block': promotion.name,
244
+                                'page': page_url})
245
+            return HttpResponseRedirect(reverse('dashboard:promotion-update',
246
+                                                kwargs=kwargs))
242 247
 
243 248
         main_form = self.get_form_class()(instance=self.object)
244 249
         ctx = self.get_context_data(form=main_form)
@@ -254,8 +259,10 @@ class UpdateView(PromotionMixin, generic.UpdateView):
254 259
         else:
255 260
             page_url = link.page_url
256 261
             link.delete()
257
-            messages.success(request, _("Content block removed from page '%s'") % page_url)
258
-        return HttpResponseRedirect(reverse('dashboard:promotion-update', kwargs=kwargs))
262
+            messages.success(request, _("Content block removed from page '%s'")
263
+                             % page_url)
264
+        return HttpResponseRedirect(reverse('dashboard:promotion-update',
265
+                                            kwargs=kwargs))
259 266
 
260 267
 
261 268
 class UpdateRawHTMLView(UpdateView):
@@ -288,7 +295,8 @@ class UpdateHandPickedProductListView(UpdateView):
288 295
         ctx = super(UpdateHandPickedProductListView,
289 296
                     self).get_context_data(**kwargs)
290 297
         if 'product_formset' not in kwargs:
291
-            ctx['product_formset'] = OrderedProductFormSet(instance=self.object)
298
+            ctx['product_formset'] \
299
+                = OrderedProductFormSet(instance=self.object)
292 300
         return ctx
293 301
 
294 302
     def form_valid(self, form):

+ 4
- 3
oscar/apps/dashboard/ranges/forms.py Datei anzeigen

@@ -52,15 +52,16 @@ class RangeProductForm(forms.Form):
52 52
 
53 53
         if len(new_ids) == 0:
54 54
             raise forms.ValidationError(
55
-                _("The products with SKUs or UPCs matching %s are already in this range") % (
56
-                    ', '.join(ids)))
55
+                _("The products with SKUs or UPCs matching %s are already in"
56
+                  " this range") % (', '.join(ids)))
57 57
 
58 58
         self.products = Product._default_manager.filter(
59 59
             Q(stockrecords__partner_sku__in=new_ids) |
60 60
             Q(upc__in=new_ids))
61 61
         if len(self.products) == 0:
62 62
             raise forms.ValidationError(
63
-                _("No products exist with a SKU or UPC matching %s") % ", ".join(ids))
63
+                _("No products exist with a SKU or UPC matching %s")
64
+                % ", ".join(ids))
64 65
 
65 66
         found_skus = set(self.products.values_list(
66 67
             'stockrecords__partner_sku', flat=True))

+ 22
- 10
oscar/apps/dashboard/ranges/models.py Datei anzeigen

@@ -9,10 +9,12 @@ Product = models.get_model('catalogue', 'Product')
9 9
 
10 10
 
11 11
 class RangeProductFileUpload(models.Model):
12
-    range = models.ForeignKey('offer.Range', related_name='file_uploads', verbose_name=_("Range"))
12
+    range = models.ForeignKey('offer.Range', related_name='file_uploads',
13
+                              verbose_name=_("Range"))
13 14
     filepath = models.CharField(_("File Path"), max_length=255)
14 15
     size = models.PositiveIntegerField(_("Size"))
15
-    uploaded_by = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("Uploaded By"))
16
+    uploaded_by = models.ForeignKey(AUTH_USER_MODEL,
17
+                                    verbose_name=_("Uploaded By"))
16 18
     date_uploaded = models.DateTimeField(_("Date Uploaded"), auto_now_add=True)
17 19
 
18 20
     PENDING, FAILED, PROCESSED = 'Pending', 'Failed', 'Processed'
@@ -21,14 +23,19 @@ class RangeProductFileUpload(models.Model):
21 23
         (FAILED, FAILED),
22 24
         (PROCESSED, PROCESSED),
23 25
     )
24
-    status = models.CharField(_("Status"), max_length=32, choices=choices, default=PENDING)
25
-    error_message = models.CharField(_("Error Message"), max_length=255, blank=True)
26
+    status = models.CharField(_("Status"), max_length=32, choices=choices,
27
+                              default=PENDING)
28
+    error_message = models.CharField(_("Error Message"), max_length=255,
29
+                                     blank=True)
26 30
 
27 31
     # Post-processing audit fields
28 32
     date_processed = models.DateTimeField(_("Date Processed"), null=True)
29
-    num_new_skus = models.PositiveIntegerField(_("Number of New SKUs"), null=True)
30
-    num_unknown_skus = models.PositiveIntegerField(_("Number of Unknown SKUs"), null=True)
31
-    num_duplicate_skus = models.PositiveIntegerField(_("Number of Duplicate SKUs"), null=True)
33
+    num_new_skus = models.PositiveIntegerField(_("Number of New SKUs"),
34
+                                               null=True)
35
+    num_unknown_skus = models.PositiveIntegerField(_("Number of Unknown SKUs"),
36
+                                                   null=True)
37
+    num_duplicate_skus = models.PositiveIntegerField(
38
+        _("Number of Duplicate SKUs"), null=True)
32 39
 
33 40
     class Meta:
34 41
         ordering = ('-date_uploaded',)
@@ -62,8 +69,11 @@ class RangeProductFileUpload(models.Model):
62 69
         """
63 70
         all_ids = set(self.extract_ids())
64 71
         products = self.range.included_products.all()
65
-        existing_skus = set(filter(bool, products.values_list('stockrecord__partner_sku', flat=True)))
66
-        existing_upcs = set(filter(bool, products.values_list('upc', flat=True)))
72
+        existing_skus = products.values_list('stockrecord__partner_sku',
73
+                                             flat=True)
74
+        existing_skus = set(filter(bool, existing_skus))
75
+        existing_upcs = products.values_list('upc', flat=True)
76
+        existing_upcs = set(filter(bool, existing_upcs))
67 77
         existing_ids = existing_skus.union(existing_upcs)
68 78
         new_ids = all_ids - existing_ids
69 79
 
@@ -74,7 +84,9 @@ class RangeProductFileUpload(models.Model):
74 84
             self.range.add_product(product)
75 85
 
76 86
         # Processing stats
77
-        found_skus = set(filter(bool, products.values_list('stockrecord__partner_sku', flat=True)))
87
+        found_skus = products.values_list('stockrecord__partner_sku',
88
+                                          flat=True)
89
+        found_skus = set(filter(bool, found_skus))
78 90
         found_upcs = set(filter(bool, products.values_list('upc', flat=True)))
79 91
         found_ids = found_skus.union(found_upcs)
80 92
         missing_ids = new_ids - found_ids

+ 3
- 3
oscar/apps/dashboard/reports/app.py Datei anzeigen

@@ -11,10 +11,10 @@ class ReportsApplication(Application):
11 11
     index_view = views.IndexView
12 12
 
13 13
     def get_urls(self):
14
-        urlpatterns = patterns('',
14
+        urls = [
15 15
             url(r'^$', self.index_view.as_view(), name='reports-index'),
16
-        )
17
-        return self.post_process_urls(urlpatterns)
16
+        ]
17
+        return self.post_process_urls(patterns('', *urls))
18 18
 
19 19
 
20 20
 application = ReportsApplication()

+ 15
- 7
oscar/apps/dashboard/reports/forms.py Datei anzeigen

@@ -2,7 +2,8 @@ from django import forms
2 2
 from django.utils.translation import ugettext_lazy as _
3 3
 
4 4
 from oscar.core.loading import get_class
5
-GeneratorRepository = get_class('dashboard.reports.utils', 'GeneratorRepository')
5
+GeneratorRepository = get_class('dashboard.reports.utils',
6
+                                'GeneratorRepository')
6 7
 
7 8
 
8 9
 class ReportForm(forms.Form):
@@ -11,16 +12,23 @@ class ReportForm(forms.Form):
11 12
     type_choices = []
12 13
     for generator in generators:
13 14
         type_choices.append((generator.code, generator.description))
14
-    report_type = forms.ChoiceField(widget=forms.Select(), choices=type_choices, label=_("Report Type"),
15
-                                    help_text=_("Only the offer and order reports "
16
-                                                "use the selected date range"))
15
+    report_type = forms.ChoiceField(widget=forms.Select(),
16
+                                    choices=type_choices,
17
+                                    label=_("Report Type"),
18
+                                    help_text=_("Only the offer and order"
19
+                                                " reports use the selected"
20
+                                                " date range"))
17 21
 
18 22
     date_from = forms.DateField(label=_("Date from"))
19 23
     date_to = forms.DateField(label=_("Date to"),
20
-                              help_text=_("The report is inclusive of this date"))
24
+                              help_text=_("The report is inclusive of this"
25
+                                          " date"))
21 26
     download = forms.BooleanField(label=_("Download"), required=False)
22 27
 
23 28
     def clean(self):
24
-        if 'date_from' in self.cleaned_data and 'date_to' in self.cleaned_data and self.cleaned_data['date_from'] > self.cleaned_data['date_to']:
25
-            raise forms.ValidationError(_("Your start date must be before your end date"))
29
+        if ('date_from' in self.cleaned_data and 'date_to' in self.cleaned_data
30
+                and self.cleaned_data['date_from'] >
31
+                self.cleaned_data['date_to']):
32
+            raise forms.ValidationError(_("Your start date must be before your"
33
+                                          " end date"))
26 34
         return self.cleaned_data

+ 0
- 2
oscar/apps/dashboard/reports/models.py Datei anzeigen

@@ -1,2 +0,0 @@
1
-# Put your models here
2
-

+ 9
- 7
oscar/apps/dashboard/reports/reports.py Datei anzeigen

@@ -20,14 +20,15 @@ class ReportGenerator(object):
20 20
             self.start_date = kwargs['start_date']
21 21
             self.end_date = kwargs['end_date']
22 22
 
23
-        self.formatter = self.formatters['%s_formatter' % kwargs['formatter']]()
23
+        formatter_name = '%s_formatter' % kwargs['formatter']
24
+        self.formatter = self.formatters[formatter_name]()
24 25
 
25 26
     def report_description(self):
26
-        return _('%(report_filter)s between %(start_date)s and %(end_date)s') % {
27
-            'report_filter': self.description,
28
-            'start_date': self.start_date,
29
-            'end_date': self.end_date,
30
-        }
27
+        return _('%(report_filter)s between %(start_date)s and %(end_date)s') \
28
+            % {'report_filter': self.description,
29
+               'start_date': self.start_date,
30
+               'end_date': self.end_date,
31
+               }
31 32
 
32 33
     def generate(self, response):
33 34
         pass
@@ -67,7 +68,8 @@ class ReportCSVFormatter(ReportFormatter):
67 68
 
68 69
     def generate_response(self, objects, **kwargs):
69 70
         response = HttpResponse(content_type='text/csv')
70
-        response['Content-Disposition'] = 'attachment; filename=%s' % self.filename(**kwargs)
71
+        response['Content-Disposition'] = 'attachment; filename=%s' \
72
+            % self.filename(**kwargs)
71 73
         self.generate_csv(response, objects)
72 74
         return response
73 75
 

+ 6
- 5
oscar/apps/dashboard/reports/utils.py Datei anzeigen

@@ -1,8 +1,11 @@
1 1
 from oscar.core.loading import get_class, get_classes
2 2
 OrderReportGenerator = get_class('order.reports', 'OrderReportGenerator')
3
-ProductReportGenerator, UserReportGenerator = get_classes('analytics.reports', ['ProductReportGenerator', 'UserReportGenerator'])
4
-OpenBasketReportGenerator, SubmittedBasketReportGenerator = get_classes(
5
-    'basket.reports', ['OpenBasketReportGenerator', 'SubmittedBasketReportGenerator'])
3
+ProductReportGenerator, UserReportGenerator \
4
+    = get_classes('analytics.reports', ['ProductReportGenerator',
5
+                                        'UserReportGenerator'])
6
+OpenBasketReportGenerator, SubmittedBasketReportGenerator \
7
+    = get_classes('basket.reports', ['OpenBasketReportGenerator',
8
+                                     'SubmittedBasketReportGenerator'])
6 9
 OfferReportGenerator = get_class('offer.reports', 'OfferReportGenerator')
7 10
 VoucherReportGenerator = get_class('voucher.reports', 'VoucherReportGenerator')
8 11
 
@@ -25,5 +28,3 @@ class GeneratorRepository(object):
25 28
             if generator.code == code:
26 29
                 return generator
27 30
         return None
28
-
29
-

+ 5
- 4
oscar/apps/dashboard/reports/views.py Datei anzeigen

@@ -5,7 +5,9 @@ from django.utils.translation import ugettext_lazy as _
5 5
 
6 6
 from oscar.core.loading import get_class
7 7
 ReportForm = get_class('dashboard.reports.forms', 'ReportForm')
8
-GeneratorRepository = get_class('dashboard.reports.utils', 'GeneratorRepository')
8
+GeneratorRepository = get_class('dashboard.reports.utils',
9
+                                'GeneratorRepository')
10
+
9 11
 
10 12
 class IndexView(ListView):
11 13
     template_name = 'dashboard/reports/index.html'
@@ -35,7 +37,8 @@ class IndexView(ListView):
35 37
             if form.is_valid():
36 38
                 generator = self._get_generator(form)
37 39
                 if not generator.is_available_to(request.user):
38
-                    return HttpResponseForbidden(_("You do not have access to this report"))
40
+                    return HttpResponseForbidden(_("You do not have access to"
41
+                                                   " this report"))
39 42
 
40 43
                 report = generator.generate()
41 44
 
@@ -54,5 +57,3 @@ class IndexView(ListView):
54 57
     def set_list_view_attrs(self, generator, report):
55 58
         self.template_name = generator.filename()
56 59
         self.object_list = self.queryset = report
57
-
58
-

+ 5
- 7
oscar/apps/dashboard/reviews/app.py Datei anzeigen

@@ -13,16 +13,14 @@ class ReviewsApplication(Application):
13 13
     delete_view = views.ReviewDeleteView
14 14
 
15 15
     def get_urls(self):
16
-        urlpatterns = patterns('',
16
+        urls = [
17 17
             url(r'^$', self.list_view.as_view(), name='reviews-list'),
18 18
             url(r'^(?P<pk>\d+)/$', self.update_view.as_view(),
19
-                name='reviews-update'
20
-            ),
19
+                name='reviews-update'),
21 20
             url(r'^(?P<pk>\d+)/delete/$', self.delete_view.as_view(),
22
-                name='reviews-delete'
23
-            ),
24
-        )
25
-        return self.post_process_urls(urlpatterns)
21
+                name='reviews-delete'),
22
+        ]
23
+        return self.post_process_urls(patterns('', *urls))
26 24
 
27 25
 
28 26
 application = ReviewsApplication()

+ 1
- 1
oscar/apps/dashboard/reviews/forms.py Datei anzeigen

@@ -6,7 +6,7 @@ ProductReview = get_model('reviews', 'productreview')
6 6
 
7 7
 
8 8
 class DashboardProductReviewForm(forms.ModelForm):
9
-    choices= (
9
+    choices = (
10 10
         (ProductReview.APPROVED, _('Approved')),
11 11
         (ProductReview.REJECTED, _('Rejected')),
12 12
     )

+ 9
- 8
oscar/apps/dashboard/reviews/utils.py Datei anzeigen

@@ -1,29 +1,30 @@
1 1
 from oscar.core.loading import get_class, get_classes
2 2
 OrderReportGenerator = get_class('order.reports', 'OrderReportGenerator')
3
-ProductReportGenerator, UserReportGenerator = get_classes('analytics.reports', ['ProductReportGenerator', 'UserReportGenerator'])
4
-OpenBasketReportGenerator, SubmittedBasketReportGenerator = get_classes(
5
-    'basket.reports', ['OpenBasketReportGenerator', 'SubmittedBasketReportGenerator'])     
3
+ProductReportGenerator, UserReportGenerator \
4
+    = get_classes('analytics.reports', ['ProductReportGenerator',
5
+                                        'UserReportGenerator'])
6
+OpenBasketReportGenerator, SubmittedBasketReportGenerator \
7
+    = get_classes('basket.reports', ['OpenBasketReportGenerator',
8
+                                     'SubmittedBasketReportGenerator'])
6 9
 OfferReportGenerator = get_class('offer.reports', 'OfferReportGenerator')
7 10
 VoucherReportGenerator = get_class('voucher.reports', 'VoucherReportGenerator')
8 11
 
9 12
 
10 13
 class GeneratorRepository(object):
11
-    
14
+
12 15
     generators = [OrderReportGenerator,
13 16
                   ProductReportGenerator,
14 17
                   UserReportGenerator,
15 18
                   OpenBasketReportGenerator,
16 19
                   SubmittedBasketReportGenerator,
17
-                  VoucherReportGenerator, 
20
+                  VoucherReportGenerator,
18 21
                   OfferReportGenerator]
19 22
 
20 23
     def get_report_generators(self):
21 24
         return self.generators
22
-    
25
+
23 26
     def get_generator(self, code):
24 27
         for generator in self.generators:
25 28
             if generator.code == code:
26 29
                 return generator
27 30
         return None
28
-    
29
-    

+ 17
- 10
oscar/apps/dashboard/reviews/views.py Datei anzeigen

@@ -52,24 +52,28 @@ class ReviewListView(BulkEditMixin, generic.ListView):
52 52
             ).filter(
53 53
                 date_created__lt=date_to
54 54
             )
55
-            self.desc_ctx['date_filter'] = _(" created between %(start_date)s and %(end_date)s") % {
56
-                'start_date': format_datetime(date_from),
57
-                'end_date': format_datetime(date_to)
58
-            }
55
+            self.desc_ctx['date_filter'] \
56
+                = _(" created between %(start_date)s and %(end_date)s") % {
57
+                    'start_date': format_datetime(date_from),
58
+                    'end_date': format_datetime(date_to)
59
+                }
59 60
         elif date_from:
60 61
             queryset = queryset.filter(date_created__gte=date_from)
61
-            self.desc_ctx['date_filter'] =  _(" created after %s") % format_datetime(date_from)
62
+            self.desc_ctx['date_filter'] \
63
+                = _(" created after %s") % format_datetime(date_from)
62 64
         elif date_to:
63 65
             # Add 24 hours to make search inclusive
64 66
             date_to = date_to + datetime.timedelta(days=1)
65 67
             queryset = queryset.filter(date_created__lt=date_to)
66
-            self.desc_ctx['date_filter'] = _(" created before %s") % format_datetime(date_to)
68
+            self.desc_ctx['date_filter'] \
69
+                = _(" created before %s") % format_datetime(date_to)
67 70
 
68 71
         return queryset
69 72
 
70 73
     def get_queryset(self):
71 74
         queryset = self.model.objects.all()
72
-        queryset = sort_queryset(queryset, self.request, ['score', 'total_votes', 'date_created'])
75
+        queryset = sort_queryset(queryset, self.request,
76
+                                 ['score', 'total_votes', 'date_created'])
73 77
         self.desc_ctx = {
74 78
             'main_filter': _('All reviews'),
75 79
             'date_filter': '',
@@ -90,14 +94,16 @@ class ReviewListView(BulkEditMixin, generic.ListView):
90 94
         if data['status'] != '':
91 95
             queryset = queryset.filter(status=data['status']).distinct()
92 96
             display_status = self.form.get_friendly_status()
93
-            self.desc_ctx['status_filter'] = _(" with status matching '%s'") % display_status
97
+            self.desc_ctx['status_filter'] \
98
+                = _(" with status matching '%s'") % display_status
94 99
 
95 100
         if data['keyword']:
96 101
             queryset = queryset.filter(
97 102
                 Q(title__icontains=data['keyword']) |
98 103
                 Q(body__icontains=data['keyword'])
99 104
             ).distinct()
100
-            self.desc_ctx['kw_filter'] = _(" with keyword matching '%s'") % data['keyword']
105
+            self.desc_ctx['kw_filter'] \
106
+                = _(" with keyword matching '%s'") % data['keyword']
101 107
 
102 108
         queryset = self.get_date_from_to_queryset(data['date_from'],
103 109
                                                   data['date_to'], queryset)
@@ -116,7 +122,8 @@ class ReviewListView(BulkEditMixin, generic.ListView):
116 122
                     Q(user__first_name__istartswith=parts[0]) |
117 123
                     Q(user__last_name__istartswith=parts[-1])
118 124
                 ).distinct()
119
-            self.desc_ctx['name_filter'] = _(" with customer name matching '%s'") % data['name']
125
+            self.desc_ctx['name_filter'] \
126
+                = _(" with customer name matching '%s'") % data['name']
120 127
 
121 128
         return queryset
122 129
 

+ 3
- 3
oscar/apps/dashboard/users/app.py Datei anzeigen

@@ -16,7 +16,7 @@ class UserManagementApplication(Application):
16 16
     alert_delete_view = views.ProductAlertDeleteView
17 17
 
18 18
     def get_urls(self):
19
-        urlpatterns = patterns('',
19
+        urls = [
20 20
             url(r'^$', self.index_view.as_view(), name='users-index'),
21 21
             url(r'^(?P<pk>\d+)/$',
22 22
                 self.user_detail_view.as_view(), name='user-detail'),
@@ -34,8 +34,8 @@ class UserManagementApplication(Application):
34 34
             url(r'^alerts/(?P<pk>\d+)/update/$',
35 35
                 self.alert_update_view.as_view(),
36 36
                 name='user-alert-update'),
37
-        )
38
-        return self.post_process_urls(urlpatterns)
37
+        ]
38
+        return self.post_process_urls(patterns('', *urls))
39 39
 
40 40
 
41 41
 application = UserManagementApplication()

+ 17
- 11
oscar/apps/dashboard/users/views.py Datei anzeigen

@@ -53,17 +53,21 @@ class IndexView(BulkEditMixin, ListView):
53 53
         if data['email']:
54 54
             email = normalise_email(data['email'])
55 55
             queryset = queryset.filter(email__startswith=email)
56
-            self.desc_ctx['email_filter'] = _(" with email matching '%s'") % email
56
+            self.desc_ctx['email_filter'] \
57
+                = _(" with email matching '%s'") % email
57 58
         if data['name']:
58
-            # If the value is two words, then assume they are first name and last name
59
+            # If the value is two words, then assume they are first name and
60
+            # last name
59 61
             parts = data['name'].split()
60 62
             if len(parts) == 2:
61
-                queryset = queryset.filter(Q(first_name__istartswith=parts[0]) |
62
-                                           Q(last_name__istartswith=parts[1])).distinct()
63
+                condition = Q(first_name__istartswith=parts[0]) \
64
+                    | Q(last_name__istartswith=parts[1])
63 65
             else:
64
-                queryset = queryset.filter(Q(first_name__istartswith=data['name']) |
65
-                                           Q(last_name__istartswith=data['name'])).distinct()
66
-            self.desc_ctx['name_filter'] = _(" with name matching '%s'") % data['name']
66
+                condition = Q(first_name__istartswith=data['name']) \
67
+                    | Q(last_name__istartswith=data['name'])
68
+            queryset = queryset.filter(condition).distinct()
69
+            self.desc_ctx['name_filter'] \
70
+                = _(" with name matching '%s'") % data['name']
67 71
 
68 72
         return queryset
69 73
 
@@ -119,7 +123,6 @@ class PasswordResetView(FormView):
119 123
         )
120 124
 
121 125
 
122
-
123 126
 class ProductAlertListView(ListView):
124 127
     model = ProductAlert
125 128
     form_class = ProductAlertSearchForm
@@ -141,7 +144,8 @@ class ProductAlertListView(ListView):
141 144
 
142 145
         if data['status']:
143 146
             queryset = queryset.filter(status=data['status']).distinct()
144
-            self.description += _(" with status matching '%s'") % data['status']
147
+            self.description \
148
+                += _(" with status matching '%s'") % data['status']
145 149
 
146 150
         if data['name']:
147 151
             # If the value is two words, then assume they are first name and
@@ -157,14 +161,16 @@ class ProductAlertListView(ListView):
157 161
                     Q(user__first_name__istartswith=parts[0]) |
158 162
                     Q(user__last_name__istartswith=parts[-1])
159 163
                 ).distinct()
160
-            self.description += _(" with customer name matching '%s'") % data['name']
164
+            self.description \
165
+                += _(" with customer name matching '%s'") % data['name']
161 166
 
162 167
         if data['email']:
163 168
             queryset = queryset.filter(
164 169
                 Q(user__email__icontains=data['email']) |
165 170
                 Q(email__icontains=data['email'])
166 171
             )
167
-            self.description += _(" with customer email matching '%s'") % data['email']
172
+            self.description \
173
+                += _(" with customer email matching '%s'") % data['email']
168 174
 
169 175
         return queryset
170 176
 

+ 8
- 5
oscar/apps/dashboard/views.py Datei anzeigen

@@ -45,8 +45,9 @@ class IndexView(TemplateView):
45 45
         ``Queryset`` of site offers is filtered by end date greater then
46 46
         the current date.
47 47
         """
48
-        return ConditionalOffer.objects.filter(end_datetime__gt=now(),
49
-                                               offer_type=ConditionalOffer.SITE)
48
+        return ConditionalOffer.objects\
49
+            .filter(end_datetime__gt=now(),
50
+                    offer_type=ConditionalOffer.SITE)
50 51
 
51 52
     def get_active_vouchers(self):
52 53
         """
@@ -92,7 +93,7 @@ class IndexView(TemplateView):
92 93
         """
93 94
         # Get datetime for 24 hours agao
94 95
         time_now = now().replace(minute=0, second=0)
95
-        start_time = time_now - timedelta(hours=hours-1)
96
+        start_time = time_now - timedelta(hours=hours - 1)
96 97
 
97 98
         orders_last_day = Order.objects.filter(date_placed__gt=start_time)
98 99
 
@@ -123,7 +124,7 @@ class IndexView(TemplateView):
123 124
 
124 125
             y_range = []
125 126
             y_axis_steps = max_value / D(str(segments))
126
-            for idx in reversed(range(segments+1)):
127
+            for idx in reversed(range(segments + 1)):
127 128
                 y_range.append(idx * y_axis_steps)
128 129
         else:
129 130
             y_range = []
@@ -146,9 +147,11 @@ class IndexView(TemplateView):
146 147
         open_alerts = StockAlert.objects.filter(status=StockAlert.OPEN)
147 148
         closed_alerts = StockAlert.objects.filter(status=StockAlert.CLOSED)
148 149
 
150
+        total_lines_last_day = Line.objects.filter(order__in=orders_last_day)\
151
+            .count(),
149 152
         stats = {
150 153
             'total_orders_last_day': orders_last_day.count(),
151
-            'total_lines_last_day': Line.objects.filter(order__in=orders_last_day).count(),
154
+            'total_lines_last_day': total_lines_last_day,
152 155
 
153 156
             'average_order_costs': orders_last_day.aggregate(
154 157
                 Avg('total_incl_tax')

+ 3
- 3
oscar/apps/dashboard/vouchers/app.py Datei anzeigen

@@ -15,7 +15,7 @@ class VoucherDashboardApplication(Application):
15 15
     stats_view = views.VoucherStatsView
16 16
 
17 17
     def get_urls(self):
18
-        urlpatterns = patterns('',
18
+        urls = [
19 19
             url(r'^$', self.list_view.as_view(), name='voucher-list'),
20 20
             url(r'^create/$', self.create_view.as_view(),
21 21
                 name='voucher-create'),
@@ -25,8 +25,8 @@ class VoucherDashboardApplication(Application):
25 25
                 name='voucher-delete'),
26 26
             url(r'^stats/(?P<pk>\d+)/$', self.stats_view.as_view(),
27 27
                 name='voucher-stats'),
28
-        )
29
-        return self.post_process_urls(urlpatterns)
28
+        ]
29
+        return self.post_process_urls(patterns('', *urls))
30 30
 
31 31
 
32 32
 application = VoucherDashboardApplication()

+ 6
- 3
oscar/apps/dashboard/vouchers/forms.py Datei anzeigen

@@ -50,7 +50,8 @@ class VoucherForm(forms.Form):
50 50
             pass
51 51
         else:
52 52
             if (not self.voucher) or (voucher.id != self.voucher.id):
53
-                raise forms.ValidationError(_("The name '%s' is already in use") % name)
53
+                raise forms.ValidationError(_("The name '%s' is already in"
54
+                                              " use") % name)
54 55
         return name
55 56
 
56 57
     def clean_code(self):
@@ -63,7 +64,8 @@ class VoucherForm(forms.Form):
63 64
             pass
64 65
         else:
65 66
             if (not self.voucher) or (voucher.id != self.voucher.id):
66
-                raise forms.ValidationError(_("The code '%s' is already in use") % code)
67
+                raise forms.ValidationError(_("The code '%s' is already in"
68
+                                              " use") % code)
67 69
         return code
68 70
 
69 71
     def clean(self):
@@ -71,7 +73,8 @@ class VoucherForm(forms.Form):
71 73
         start_date = cleaned_data.get('start_date', None)
72 74
         end_date = cleaned_data.get('end_date', None)
73 75
         if start_date and end_date and end_date < start_date:
74
-            raise forms.ValidationError(_("The start date must be before the end date"))
76
+            raise forms.ValidationError(_("The start date must be before the"
77
+                                          " end date"))
75 78
         return cleaned_data
76 79
 
77 80
 

+ 10
- 5
oscar/apps/dashboard/vouchers/views.py Datei anzeigen

@@ -29,8 +29,9 @@ class VoucherListView(ListView):
29 29
     def get_queryset(self):
30 30
         qs = self.model.objects.all().order_by('-date_created')
31 31
         qs = sort_queryset(qs, self.request,
32
-            ['num_basket_additions', 'num_orders', 'date_created'],
33
-            '-date_created')
32
+                           ['num_basket_additions', 'num_orders',
33
+                            'date_created'],
34
+                           '-date_created')
34 35
         self.description_ctx = {'main_filter': _('All vouchers'),
35 36
                                 'name_filter': '',
36 37
                                 'code_filter': ''}
@@ -47,10 +48,12 @@ class VoucherListView(ListView):
47 48
         data = self.form.cleaned_data
48 49
         if data['name']:
49 50
             qs = qs.filter(name__icontains=data['name'])
50
-            self.description_ctx['name_filter'] = _("with name matching '%s'") % data['name']
51
+            self.description_ctx['name_filter'] \
52
+                = _("with name matching '%s'") % data['name']
51 53
         if data['code']:
52 54
             qs = qs.filter(code=data['code'])
53
-            self.description_ctx['code_filter'] = _("with code '%s'") % data['code']
55
+            self.description_ctx['code_filter'] \
56
+                = _("with code '%s'") % data['code']
54 57
         if data['is_active']:
55 58
             today = datetime.date.today()
56 59
             qs = qs.filter(start_date__lte=today, end_date__gte=today)
@@ -116,7 +119,9 @@ class VoucherStatsView(DetailView):
116 119
 
117 120
     def get_context_data(self, **kwargs):
118 121
         ctx = super(VoucherStatsView, self).get_context_data(**kwargs)
119
-        ctx['discounts'] = OrderDiscount.objects.filter(voucher_id=self.object.id).order_by('-order__date_placed')
122
+        discounts = OrderDiscount.objects.filter(voucher_id=self.object.id)
123
+        discounts = discounts.order_by('-order__date_placed')
124
+        ctx['discounts'] = discounts
120 125
         return ctx
121 126
 
122 127
 

+ 2
- 1
oscar/apps/offer/admin.py Datei anzeigen

@@ -16,7 +16,8 @@ class BenefitAdmin(admin.ModelAdmin):
16 16
 
17 17
 
18 18
 class ConditionalOfferAdmin(admin.ModelAdmin):
19
-    list_display = ('name', 'offer_type', 'start_datetime', 'end_datetime', 'condition', 'benefit', 'total_discount')
19
+    list_display = ('name', 'offer_type', 'start_datetime', 'end_datetime',
20
+                    'condition', 'benefit', 'total_discount')
20 21
     list_filter = ('offer_type',)
21 22
     readonly_fields = ('total_discount', 'num_orders')
22 23
     fieldsets = (

+ 5
- 4
oscar/apps/offer/app.py Datei anzeigen

@@ -10,11 +10,12 @@ class OfferApplication(Application):
10 10
     list_view = views.OfferListView
11 11
 
12 12
     def get_urls(self):
13
-        urlpatterns = patterns('',
13
+        urls = [
14 14
             url(r'^$', self.list_view.as_view(), name='list'),
15
-            url(r'^(?P<slug>[\w-]+)/$', self.detail_view.as_view(), name='detail'),
16
-        )
17
-        return self.post_process_urls(urlpatterns)
15
+            url(r'^(?P<slug>[\w-]+)/$', self.detail_view.as_view(),
16
+                name='detail'),
17
+        ]
18
+        return self.post_process_urls(patterns('', *urls))
18 19
 
19 20
 
20 21
 application = OfferApplication()

+ 55
- 48
oscar/apps/offer/models.py Datei anzeigen

@@ -67,7 +67,8 @@ class ConditionalOffer(models.Model):
67 67
         help_text=_("This is displayed within the customer's basket"))
68 68
     slug = models.SlugField(_("Slug"), max_length=128, unique=True, null=True)
69 69
     description = models.TextField(_("Description"), blank=True,
70
-        help_text=_("This is displayed on the offer browsing page"))
70
+                                   help_text=_("This is displayed on the offer"
71
+                                               " browsing page"))
71 72
 
72 73
     # Offers come in a few different types:
73 74
     # (a) Offers that are available to all customers on the site.  Eg a
@@ -299,9 +300,9 @@ class ConditionalOffer(models.Model):
299 300
 
300 301
     def get_num_user_applications(self, user):
301 302
         OrderDiscount = models.get_model('order', 'OrderDiscount')
302
-        aggregates = OrderDiscount.objects.filter(
303
-            offer_id=self.id, order__user=user).aggregate(
304
-                total=models.Sum('frequency'))
303
+        aggregates = OrderDiscount.objects.filter(offer_id=self.id,
304
+                                                  order__user=user)\
305
+            .aggregate(total=models.Sum('frequency'))
305 306
         return aggregates['total'] if aggregates['total'] is not None else 0
306 307
 
307 308
     def shipping_discount(self, charge):
@@ -331,33 +332,27 @@ class ConditionalOffer(models.Model):
331 332
 
332 333
         if self.max_global_applications:
333 334
             remaining = self.max_global_applications - self.num_applications
334
-            desc = _(
335
-                "Limited to %(total)d uses "
336
-                "(%(remainder)d remaining)") % {
337
-                    'total': self.max_global_applications,
338
-                    'remainder': remaining}
339
-            restrictions.append({
340
-                'description': desc,
341
-                'is_satisfied': remaining > 0})
335
+            desc = _("Limited to %(total)d uses (%(remainder)d remaining)") \
336
+                % {'total': self.max_global_applications,
337
+                   'remainder': remaining}
338
+            restrictions.append({'description': desc,
339
+                                 'is_satisfied': remaining > 0})
342 340
 
343 341
         if self.max_user_applications:
344 342
             if self.max_user_applications == 1:
345 343
                 desc = _("Limited to 1 use per user")
346 344
             else:
347
-                desc = _(
348
-                    "Limited to %(total)d uses per user") % {
349
-                        'total': self.max_user_applications}
350
-            restrictions.append({
351
-                'description': desc,
352
-                'is_satisfied': True})
345
+                desc = _("Limited to %(total)d uses per user") \
346
+                    % {'total': self.max_user_applications}
347
+            restrictions.append({'description': desc,
348
+                                 'is_satisfied': True})
353 349
 
354 350
         if self.max_basket_applications:
355 351
             if self.max_user_applications == 1:
356 352
                 desc = _("Limited to 1 use per basket")
357 353
             else:
358
-                desc = _(
359
-                    "Limited to %(total)d uses per basket") % {
360
-                        'total': self.max_basket_applications}
354
+                desc = _("Limited to %(total)d uses per basket") \
355
+                    % {'total': self.max_basket_applications}
361 356
             restrictions.append({
362 357
                 'description': desc,
363 358
                 'is_satisfied': True})
@@ -372,10 +367,11 @@ class ConditionalOffer(models.Model):
372 367
         if self.start_datetime or self.end_datetime:
373 368
             today = now()
374 369
             if self.start_datetime and self.end_datetime:
375
-                desc = _("Available between %(start)s and %(end)s") % {
376
-                        'start': hide_time_if_zero(self.start_datetime),
377
-                        'end': hide_time_if_zero(self.end_datetime)}
378
-                is_satisfied = self.start_datetime <= today <= self.end_datetime
370
+                desc = _("Available between %(start)s and %(end)s") \
371
+                    % {'start': hide_time_if_zero(self.start_datetime),
372
+                       'end': hide_time_if_zero(self.end_datetime)}
373
+                is_satisfied \
374
+                    = self.start_datetime <= today <= self.end_datetime
379 375
             elif self.start_datetime:
380 376
                 desc = _("Available from %(start)s") % {
381 377
                     'start': hide_time_if_zero(self.start_datetime)}
@@ -412,11 +408,11 @@ class ConditionalOffer(models.Model):
412 408
         cond_range = self.condition.range
413 409
         if cond_range.includes_all_products:
414 410
             # Return ALL the products
415
-            return Product.browsable.select_related(
416
-                'product_class', 'stockrecord').filter(
417
-                    is_discountable=True).prefetch_related(
418
-                        'variants', 'images', 'product_class__options',
419
-                        'product_options')
411
+            return Product.browsable.select_related('product_class',
412
+                                                    'stockrecord')\
413
+                .filter(is_discountable=True)\
414
+                .prefetch_related('variants', 'images',
415
+                                  'product_class__options', 'product_options')
420 416
         return cond_range.included_products.filter(is_discountable=True)
421 417
 
422 418
 
@@ -541,7 +537,8 @@ class Benefit(models.Model):
541 537
         (SHIPPING_ABSOLUTE,
542 538
          _("Discount is a fixed amount of the shipping cost")),
543 539
         (SHIPPING_FIXED_PRICE, _("Get shipping for a fixed price")),
544
-        (SHIPPING_PERCENTAGE, _("Discount is a percentage off of the shipping cost")),
540
+        (SHIPPING_PERCENTAGE, _("Discount is a percentage off of the shipping"
541
+                                " cost")),
545 542
     )
546 543
     type = models.CharField(
547 544
         _("Type"), max_length=128, choices=TYPE_CHOICES, blank=True)
@@ -844,7 +841,7 @@ class Range(models.Model):
844 841
         # the tests that require more database queries.
845 842
 
846 843
         if settings.OSCAR_OFFER_BLACKLIST_PRODUCT and \
847
-            settings.OSCAR_OFFER_BLACKLIST_PRODUCT(product):
844
+                settings.OSCAR_OFFER_BLACKLIST_PRODUCT(product):
848 845
             return False
849 846
 
850 847
         # Delegate to a proxy class if one is provided
@@ -865,7 +862,8 @@ class Range(models.Model):
865 862
         if test_categories:
866 863
             for category in product.categories.all():
867 864
                 for test_category in test_categories:
868
-                    if category == test_category or category.is_descendant_of(test_category):
865
+                    if category == test_category \
866
+                            or category.is_descendant_of(test_category):
869 867
                         return True
870 868
         return False
871 869
 
@@ -874,14 +872,16 @@ class Range(models.Model):
874 872
 
875 873
     def _included_product_ids(self):
876 874
         if self.__included_product_ids is None:
877
-            self.__included_product_ids = [row['id'] for row in self.included_products.values('id')]
875
+            self.__included_product_ids = [row['id'] for row in
876
+                                           self.included_products.values('id')]
878 877
         return self.__included_product_ids
879 878
 
880 879
     def _excluded_product_ids(self):
881 880
         if not self.id:
882 881
             return []
883 882
         if self.__excluded_product_ids is None:
884
-            self.__excluded_product_ids = [row['id'] for row in self.excluded_products.values('id')]
883
+            self.__excluded_product_ids = [row['id'] for row in
884
+                                           self.excluded_products.values('id')]
885 885
         return self.__excluded_product_ids
886 886
 
887 887
     def _class_ids(self):
@@ -959,7 +959,7 @@ class CountCondition(Condition):
959 959
         num_matches = 0
960 960
         for line in basket.all_lines():
961 961
             if (self.can_apply_condition(line)
962
-                and line.quantity_without_discount > 0):
962
+                    and line.quantity_without_discount > 0):
963 963
                 num_matches += line.quantity_without_discount
964 964
         self._num_matches = num_matches
965 965
         return num_matches
@@ -972,8 +972,8 @@ class CountCondition(Condition):
972 972
         num_matches = self._get_num_matches(basket)
973 973
         delta = self.value - num_matches
974 974
         return ungettext('Buy %(delta)d more product from %(range)s',
975
-                         'Buy %(delta)d more products from %(range)s', delta) % {
976
-                            'delta': delta, 'range': self.range}
975
+                         'Buy %(delta)d more products from %(range)s', delta) \
976
+            % {'delta': delta, 'range': self.range}
977 977
 
978 978
     def consume_items(self, offer, basket, affected_lines):
979 979
         """
@@ -1008,7 +1008,8 @@ class CoverageCondition(Condition):
1008 1008
     An offer condition dependent on the number of DISTINCT matching items from
1009 1009
     the basket.
1010 1010
     """
1011
-    _description = _("Basket includes %(count)d distinct item(s) from %(range)s")
1011
+    _description = _("Basket includes %(count)d distinct item(s) from"
1012
+                     " %(range)s")
1012 1013
 
1013 1014
     @property
1014 1015
     def name(self):
@@ -1036,7 +1037,8 @@ class CoverageCondition(Condition):
1036 1037
             if not line.is_available_for_discount:
1037 1038
                 continue
1038 1039
             product = line.product
1039
-            if (self.can_apply_condition(line) and product.id not in covered_ids):
1040
+            if (self.can_apply_condition(line) and product.id not in
1041
+                    covered_ids):
1040 1042
                 covered_ids.append(product.id)
1041 1043
             if len(covered_ids) >= self.value:
1042 1044
                 return True
@@ -1048,15 +1050,16 @@ class CoverageCondition(Condition):
1048 1050
             if not line.is_available_for_discount:
1049 1051
                 continue
1050 1052
             product = line.product
1051
-            if (self.can_apply_condition(line) and product.id not in covered_ids):
1053
+            if (self.can_apply_condition(line) and product.id not in
1054
+                    covered_ids):
1052 1055
                 covered_ids.append(product.id)
1053 1056
         return len(covered_ids)
1054 1057
 
1055
-    def get_upsell_message(self, offer,  basket):
1058
+    def get_upsell_message(self, offer, basket):
1056 1059
         delta = self.value - self._get_num_covered_products(basket)
1057 1060
         return ungettext('Buy %(delta)d more product from %(range)s',
1058
-                         'Buy %(delta)d more products from %(range)s', delta) % {
1059
-                         'delta': delta, 'range': self.range}
1061
+                         'Buy %(delta)d more products from %(range)s', delta) \
1062
+            % {'delta': delta, 'range': self.range}
1060 1063
 
1061 1064
     def is_partially_satisfied(self, offer, basket):
1062 1065
         return 0 < self._get_num_covered_products(basket) < self.value
@@ -1095,7 +1098,8 @@ class CoverageCondition(Condition):
1095 1098
         covered_ids = []
1096 1099
         value = D('0.00')
1097 1100
         for line in basket.all_lines():
1098
-            if (self.can_apply_condition(line) and line.product.id not in covered_ids):
1101
+            if (self.can_apply_condition(line) and line.product.id not in
1102
+                    covered_ids):
1099 1103
                 covered_ids.append(line.product.id)
1100 1104
                 value += unit_price(offer, line)
1101 1105
             if len(covered_ids) >= self.value:
@@ -1133,7 +1137,8 @@ class ValueCondition(Condition):
1133 1137
         """
1134 1138
         value_of_matches = D('0.00')
1135 1139
         for line in basket.all_lines():
1136
-            if (self.can_apply_condition(line) and line.quantity_without_discount > 0):
1140
+            if (self.can_apply_condition(line) and
1141
+                    line.quantity_without_discount > 0):
1137 1142
                 price = unit_price(offer, line)
1138 1143
                 value_of_matches += price * int(line.quantity_without_discount)
1139 1144
             if value_of_matches >= self.value:
@@ -1145,7 +1150,8 @@ class ValueCondition(Condition):
1145 1150
             return getattr(self, '_value_of_matches')
1146 1151
         value_of_matches = D('0.00')
1147 1152
         for line in basket.all_lines():
1148
-            if (self.can_apply_condition(line) and line.quantity_without_discount > 0):
1153
+            if (self.can_apply_condition(line) and
1154
+                    line.quantity_without_discount > 0):
1149 1155
                 price = unit_price(offer, line)
1150 1156
                 value_of_matches += price * int(line.quantity_without_discount)
1151 1157
         self._value_of_matches = value_of_matches
@@ -1423,7 +1429,8 @@ class FixedPriceBenefit(Benefit):
1423 1429
 
1424 1430
         # Fetch basket lines that are in the range and available to be used in
1425 1431
         # an offer.
1426
-        line_tuples = self.get_applicable_lines(offer, basket, range=condition.range)
1432
+        line_tuples = self.get_applicable_lines(offer, basket,
1433
+                                                range=condition.range)
1427 1434
         if not line_tuples:
1428 1435
             return ZERO_DISCOUNT
1429 1436
 

+ 3
- 2
oscar/apps/offer/receivers.py Datei anzeigen

@@ -10,8 +10,9 @@ ConditionalOffer = get_model('offer', 'ConditionalOffer')
10 10
 
11 11
 @receiver(m2m_changed)
12 12
 def receive_basket_voucher_change(sender, **kwargs):
13
-    if (kwargs['model'] == Voucher and kwargs['action'] == 'post_add' and
14
-        isinstance(kwargs['instance'], AbstractBasket) and kwargs['pk_set']):
13
+    if (kwargs['model'] == Voucher and kwargs['action'] == 'post_add'
14
+            and isinstance(kwargs['instance'], AbstractBasket)
15
+            and kwargs['pk_set']):
15 16
         voucher_id = list(kwargs['pk_set'])[0]
16 17
         voucher = Voucher._default_manager.get(pk=voucher_id)
17 18
         voucher.num_basket_additions += 1

+ 9
- 5
oscar/apps/offer/reports.py Datei anzeigen

@@ -6,8 +6,10 @@ from django.utils.translation import ugettext_lazy as _
6 6
 
7 7
 from oscar.core.loading import get_class
8 8
 ReportGenerator = get_class('dashboard.reports.reports', 'ReportGenerator')
9
-ReportCSVFormatter = get_class('dashboard.reports.reports', 'ReportCSVFormatter')
10
-ReportHTMLFormatter = get_class('dashboard.reports.reports', 'ReportHTMLFormatter')
9
+ReportCSVFormatter = get_class('dashboard.reports.reports',
10
+                               'ReportCSVFormatter')
11
+ReportHTMLFormatter = get_class('dashboard.reports.reports',
12
+                                'ReportHTMLFormatter')
11 13
 ConditionalOffer = get_model('offer', 'ConditionalOffer')
12 14
 OrderDiscount = get_model('order', 'OrderDiscount')
13 15
 
@@ -19,7 +21,7 @@ class OfferReportCSVFormatter(ReportCSVFormatter):
19 21
         writer = self.get_csv_writer(response)
20 22
         header_row = [_('Offer'),
21 23
                       _('Total discount')
22
-                     ]
24
+                      ]
23 25
         writer.writerow(header_row)
24 26
 
25 27
         for offer in offers:
@@ -49,13 +51,15 @@ class OfferReportGenerator(ReportGenerator):
49 51
         for discount in discounts:
50 52
             if discount.offer_id not in offer_discounts:
51 53
                 try:
52
-                    offer = ConditionalOffer._default_manager.get(id=discount.offer_id)
54
+                    all_offers = ConditionalOffer._default_manager
55
+                    offer = all_offers.get(id=discount.offer_id)
53 56
                 except ConditionalOffer.DoesNotExist:
54 57
                     continue
55 58
                 offer_discounts[discount.offer_id] = {
56 59
                     'offer': offer,
57 60
                     'total_discount': D('0.00')
58 61
                 }
59
-            offer_discounts[discount.offer_id]['total_discount'] += discount.amount
62
+            offer_discounts[discount.offer_id]['total_discount'] \
63
+                += discount.amount
60 64
 
61 65
         return self.formatter.generate_response(offer_discounts.values())

+ 31
- 23
oscar/apps/order/abstract_models.py Datei anzeigen

@@ -76,13 +76,13 @@ class AbstractOrder(models.Model):
76 76
     #: Order status pipeline.  This should be a dict where each (key, value) #:
77 77
     #: corresponds to a status and a list of possible statuses that can follow
78 78
     #: that one.
79
-    pipeline = getattr(settings,  'OSCAR_ORDER_STATUS_PIPELINE', {})
79
+    pipeline = getattr(settings, 'OSCAR_ORDER_STATUS_PIPELINE', {})
80 80
 
81 81
     #: Order status cascade pipeline.  This should be a dict where each (key,
82 82
     #: value) pair corresponds to an *order* status and the corresponding
83 83
     #: *line* status that needs to be set when the order is set to the new
84 84
     #: status
85
-    cascade = getattr(settings,  'OSCAR_ORDER_STATUS_CASCADE', {})
85
+    cascade = getattr(settings, 'OSCAR_ORDER_STATUS_CASCADE', {})
86 86
 
87 87
     @classmethod
88 88
     def all_statuses(cls):
@@ -107,11 +107,12 @@ class AbstractOrder(models.Model):
107 107
         if new_status == self.status:
108 108
             return
109 109
         if new_status not in self.available_statuses():
110
-            raise exceptions.InvalidOrderStatus(_("'%(new_status)s' is not a valid status for order %(number)s "
111
-                                       "(current status: '%(status)s')") % {
112
-                                            'new_status': new_status,
113
-                                            'number': self.number,
114
-                                            'status': self.status})
110
+            raise exceptions.InvalidOrderStatus(
111
+                _("'%(new_status)s' is not a valid status for order %(number)s"
112
+                  " (current status: '%(status)s')")
113
+                % {'new_status': new_status,
114
+                   'number': self.number,
115
+                   'status': self.status})
115 116
         self.status = new_status
116 117
         if new_status in self.cascade:
117 118
             for line in self.lines.all():
@@ -219,7 +220,8 @@ class AbstractOrder(models.Model):
219 220
             event_name = event.event_type.name
220 221
             if event_name not in map:
221 222
                 map[event_name] = []
222
-            map[event_name] = list(chain(map[event_name], event.line_quantities.all()))
223
+            map[event_name] = list(chain(map[event_name],
224
+                                         event.line_quantities.all()))
223 225
 
224 226
         # Determine last complete event
225 227
         status = _("In progress")
@@ -256,7 +258,7 @@ class AbstractOrder(models.Model):
256 258
 
257 259
     class Meta:
258 260
         abstract = True
259
-        ordering = ['-date_placed',]
261
+        ordering = ['-date_placed']
260 262
         verbose_name = _("Order")
261 263
         verbose_name_plural = _("Orders")
262 264
 
@@ -264,7 +266,8 @@ class AbstractOrder(models.Model):
264 266
         return u"#%s" % (self.number,)
265 267
 
266 268
     def verification_hash(self):
267
-        return hashlib.md5('%s%s' % (self.number, settings.SECRET_KEY)).hexdigest()
269
+        hash = hashlib.md5('%s%s' % (self.number, settings.SECRET_KEY))
270
+        return hash.hexdigest()
268 271
 
269 272
     @property
270 273
     def email(self):
@@ -297,11 +300,13 @@ class AbstractOrderNote(models.Model):
297 300
     This are often used for audit purposes too.  IE, whenever an admin
298 301
     makes a change to an order, we create a note to record what happened.
299 302
     """
300
-    order = models.ForeignKey('order.Order', related_name="notes", verbose_name=_("Order"))
303
+    order = models.ForeignKey('order.Order', related_name="notes",
304
+                              verbose_name=_("Order"))
301 305
 
302 306
     # These are sometimes programatically generated so don't need a
303 307
     # user everytime
304
-    user = models.ForeignKey(AUTH_USER_MODEL, null=True, verbose_name=_("User"))
308
+    user = models.ForeignKey(AUTH_USER_MODEL, null=True,
309
+                             verbose_name=_("User"))
305 310
 
306 311
     # We allow notes to be classified although this isn't always needed
307 312
     INFO, WARNING, ERROR, SYSTEM = 'Info', 'Warning', 'Error', 'System'
@@ -348,7 +353,8 @@ class AbstractCommunicationEvent(models.Model):
348 353
         ordering = ['-date_created']
349 354
 
350 355
     def __unicode__(self):
351
-        return _("'%(type)s' event for order #%(number)s") % {'type': self.event_type.name, 'number': self.order.number}
356
+        return _("'%(type)s' event for order #%(number)s") \
357
+            % {'type': self.event_type.name, 'number': self.order.number}
352 358
 
353 359
 
354 360
 # LINES
@@ -432,7 +438,7 @@ class AbstractLine(models.Model):
432 438
     # Partners often want to assign some status to each line to help with their
433 439
     # own business processes.
434 440
     status = models.CharField(_("Status"), max_length=255,
435
-                             null=True, blank=True)
441
+                              null=True, blank=True)
436 442
 
437 443
     # Estimated dispatch date - should be set at order time
438 444
     est_dispatch_date = models.DateField(
@@ -441,7 +447,7 @@ class AbstractLine(models.Model):
441 447
     #: Order status pipeline.  This should be a dict where each (key, value)
442 448
     #: corresponds to a status and the possible statuses that can follow that
443 449
     #: one.
444
-    pipeline = getattr(settings,  'OSCAR_LINE_STATUS_PIPELINE', {})
450
+    pipeline = getattr(settings, 'OSCAR_LINE_STATUS_PIPELINE', {})
445 451
 
446 452
     class Meta:
447 453
         abstract = True
@@ -479,8 +485,10 @@ class AbstractLine(models.Model):
479 485
         if new_status == self.status:
480 486
             return
481 487
         if new_status not in self.available_statuses():
482
-            raise exceptions.InvalidLineStatus(_("'%(new_status)s' is not a valid status (current status: '%(status)s')") % {
483
-                                    'new_status': new_status, 'status': self.status})
488
+            raise exceptions.InvalidLineStatus(
489
+                _("'%(new_status)s' is not a valid status (current status:"
490
+                  " '%(status)s')")
491
+                % {'new_status': new_status, 'status': self.status})
484 492
         self.status = new_status
485 493
         self.save()
486 494
     set_status.alters_data = True
@@ -508,11 +516,13 @@ class AbstractLine(models.Model):
508 516
 
509 517
     @property
510 518
     def discount_incl_tax(self):
511
-        return self.line_price_before_discounts_incl_tax - self.line_price_incl_tax
519
+        return self.line_price_before_discounts_incl_tax \
520
+            - self.line_price_incl_tax
512 521
 
513 522
     @property
514 523
     def discount_excl_tax(self):
515
-        return self.line_price_before_discounts_excl_tax - self.line_price_excl_tax
524
+        return self.line_price_before_discounts_excl_tax \
525
+            - self.line_price_excl_tax
516 526
 
517 527
     @property
518 528
     def line_price_tax(self):
@@ -568,8 +578,7 @@ class AbstractLine(models.Model):
568 578
         event of the passed type.
569 579
         """
570 580
         result = self.shipping_event_quantities.filter(
571
-            event__event_type=event_type).aggregate(
572
-                Sum('quantity'))
581
+            event__event_type=event_type).aggregate(Sum('quantity'))
573 582
         if result['quantity__sum'] is None:
574 583
             return 0
575 584
         else:
@@ -616,8 +625,7 @@ class AbstractLine(models.Model):
616 625
         event of the passed type.
617 626
         """
618 627
         result = self.payment_event_quantities.filter(
619
-            event__event_type=event_type).aggregate(
620
-                Sum('quantity'))
628
+            event__event_type=event_type).aggregate(Sum('quantity'))
621 629
         if result['quantity__sum'] is None:
622 630
             return 0
623 631
         else:

+ 4
- 6
oscar/apps/order/models.py Datei anzeigen

@@ -1,5 +1,6 @@
1
-from oscar.apps.order.abstract_models import *
2
-from oscar.apps.address.abstract_models import AbstractShippingAddress, AbstractBillingAddress
1
+from oscar.apps.order.abstract_models import *  # noqa
2
+from oscar.apps.address.abstract_models import (AbstractShippingAddress,
3
+                                                AbstractBillingAddress)
3 4
 
4 5
 
5 6
 class Order(AbstractOrder):
@@ -20,7 +21,7 @@ class ShippingAddress(AbstractShippingAddress):
20 21
 
21 22
 class BillingAddress(AbstractBillingAddress):
22 23
     pass
23
-    
24
+
24 25
 
25 26
 class Line(AbstractLine):
26 27
     pass
@@ -52,6 +53,3 @@ class PaymentEventType(AbstractPaymentEventType):
52 53
 
53 54
 class OrderDiscount(AbstractOrderDiscount):
54 55
     pass
55
-
56
-
57
-    

+ 4
- 4
oscar/apps/order/processing.py Datei anzeigen

@@ -82,8 +82,8 @@ class EventHandler(object):
82 82
             # 'is_shipping_event_permitted' and enforce the correct order of
83 83
             # shipping events.
84 84
             if not line.is_shipping_event_permitted(event_type, qty):
85
-                msg = _("The selected quantity for line #%(line_id)s is too large") % {
86
-                    'line_id': line.id}
85
+                msg = _("The selected quantity for line #%(line_id)s is too"
86
+                        " large") % {'line_id': line.id}
87 87
                 errors.append(msg)
88 88
         if errors:
89 89
             raise exceptions.InvalidShippingEvent(", ".join(errors))
@@ -93,8 +93,8 @@ class EventHandler(object):
93 93
         errors = []
94 94
         for line, qty in zip(lines, line_quantities):
95 95
             if not line.is_payment_event_permitted(event_type, qty):
96
-                msg = _("The selected quantity for line #%(line_id)s is too large") % {
97
-                    'line_id': line.id}
96
+                msg = _("The selected quantity for line #%(line_id)s is too"
97
+                        " large") % {'line_id': line.id}
98 98
                 errors.append(msg)
99 99
         if errors:
100 100
             raise exceptions.InvalidPaymentEvent(", ".join(errors))

+ 4
- 2
oscar/apps/order/reports.py Datei anzeigen

@@ -5,8 +5,10 @@ from django.utils.translation import ugettext_lazy as _
5 5
 
6 6
 from oscar.core.loading import get_class
7 7
 ReportGenerator = get_class('dashboard.reports.reports', 'ReportGenerator')
8
-ReportCSVFormatter = get_class('dashboard.reports.reports', 'ReportCSVFormatter')
9
-ReportHTMLFormatter = get_class('dashboard.reports.reports', 'ReportHTMLFormatter')
8
+ReportCSVFormatter = get_class('dashboard.reports.reports',
9
+                               'ReportCSVFormatter')
10
+ReportHTMLFormatter = get_class('dashboard.reports.reports',
11
+                                'ReportHTMLFormatter')
10 12
 Order = get_model('order', 'Order')
11 13
 
12 14
 

+ 1
- 1
oscar/apps/order/signals.py Datei anzeigen

@@ -1,3 +1,3 @@
1 1
 import django.dispatch
2 2
 
3
-order_placed = django.dispatch.Signal(providing_args=["order", "user"])
3
+order_placed = django.dispatch.Signal(providing_args=["order", "user"])

+ 16
- 9
oscar/apps/order/utils.py Datei anzeigen

@@ -60,7 +60,8 @@ class OrderCreator(object):
60 60
         except Order.DoesNotExist:
61 61
             pass
62 62
         else:
63
-            raise ValueError(_("There is already an order with number %s") % order_number)
63
+            raise ValueError(_("There is already an order with number %s")
64
+                             % order_number)
64 65
 
65 66
         # Ok - everything seems to be in order, let's place the order
66 67
         order = self.create_order_model(
@@ -73,7 +74,8 @@ class OrderCreator(object):
73 74
         for application in basket.offer_applications:
74 75
             # Trigger any deferred benefits from offers and capture the
75 76
             # resulting message
76
-            application['message'] = application['offer'].apply_deferred_benefit(basket)
77
+            application['message'] \
78
+                = application['offer'].apply_deferred_benefit(basket)
77 79
             # Record offer application results
78 80
             if application['result'].affects_shipping:
79 81
                 # Skip zero shipping discounts
@@ -94,8 +96,8 @@ class OrderCreator(object):
94 96
 
95 97
         return order
96 98
 
97
-    def create_order_model(self, user, basket, shipping_address, shipping_method,
98
-                           billing_address, total,
99
+    def create_order_model(self, user, basket, shipping_address,
100
+                           shipping_method, billing_address, total,
99 101
                            order_number, status, **extra_order_fields):
100 102
         """
101 103
         Creates an order model.
@@ -150,17 +152,22 @@ class OrderCreator(object):
150 152
             'upc': product.upc,
151 153
             'quantity': basket_line.quantity,
152 154
             # Price details
153
-            'line_price_excl_tax': basket_line.line_price_excl_tax_incl_discounts,
154
-            'line_price_incl_tax': basket_line.line_price_incl_tax_incl_discounts,
155
-            'line_price_before_discounts_excl_tax': basket_line.line_price_excl_tax,
156
-            'line_price_before_discounts_incl_tax': basket_line.line_price_incl_tax,
155
+            'line_price_excl_tax':
156
+            basket_line.line_price_excl_tax_incl_discounts,
157
+            'line_price_incl_tax':
158
+            basket_line.line_price_incl_tax_incl_discounts,
159
+            'line_price_before_discounts_excl_tax':
160
+            basket_line.line_price_excl_tax,
161
+            'line_price_before_discounts_incl_tax':
162
+            basket_line.line_price_incl_tax,
157 163
             # Reporting details
158 164
             'unit_cost_price': stockrecord.cost_price,
159 165
             'unit_price_incl_tax': basket_line.unit_price_incl_tax,
160 166
             'unit_price_excl_tax': basket_line.unit_price_excl_tax,
161 167
             'unit_retail_price': stockrecord.price_retail,
162 168
             # Shipping details
163
-            'est_dispatch_date': basket_line.stockinfo.availability.dispatch_date
169
+            'est_dispatch_date':
170
+            basket_line.stockinfo.availability.dispatch_date
164 171
         }
165 172
         extra_line_fields = extra_line_fields or {}
166 173
         if hasattr(settings, 'OSCAR_INITIAL_LINE_STATUS'):

+ 4
- 3
oscar/apps/partner/abstract_models.py Datei anzeigen

@@ -284,8 +284,8 @@ class AbstractStockRecord(models.Model):
284 284
             "removed in 0.7.  Use a strategy class to determine availability "
285 285
             "instead"), DeprecationWarning)
286 286
         return get_partner_wrapper(
287
-            self.partner_id).is_purchase_permitted(
288
-                self, user, quantity, product)
287
+            self.partner_id).is_purchase_permitted(self, user, quantity,
288
+                                                   product)
289 289
 
290 290
     @property
291 291
     def availability_code(self):
@@ -399,7 +399,8 @@ class AbstractStockAlert(models.Model):
399 399
     close.alters_data = True
400 400
 
401 401
     def __unicode__(self):
402
-        return _('<stockalert for "%(stock)s" status %(status)s>') % {'stock': self.stockrecord, 'status': self.status}
402
+        return _('<stockalert for "%(stock)s" status %(status)s>') \
403
+            % {'stock': self.stockrecord, 'status': self.status}
403 404
 
404 405
     class Meta:
405 406
         abstract = True

+ 3
- 2
oscar/apps/partner/admin.py Datei anzeigen

@@ -6,9 +6,10 @@ StockRecord = get_model('partner', 'StockRecord')
6 6
 
7 7
 
8 8
 class StockRecordAdmin(admin.ModelAdmin):
9
-    list_display = ('product', 'partner', 'partner_sku', 'price_excl_tax', 'cost_price', 'num_in_stock')
9
+    list_display = ('product', 'partner', 'partner_sku', 'price_excl_tax',
10
+                    'cost_price', 'num_in_stock')
10 11
     list_filter = ('partner',)
11
-    
12
+
12 13
 
13 14
 admin.site.register(Partner)
14 15
 admin.site.register(StockRecord, StockRecordAdmin)

+ 1
- 1
oscar/apps/partner/models.py Datei anzeigen

@@ -19,4 +19,4 @@ class StockAlert(AbstractStockAlert):
19 19
     pass
20 20
 
21 21
 
22
-from oscar.apps.partner.receivers import *
22
+from oscar.apps.partner.receivers import *  # noqa

+ 2
- 1
oscar/apps/partner/receivers.py Datei anzeigen

@@ -2,7 +2,8 @@ from django.dispatch import receiver
2 2
 from django.db.models.signals import post_save
3 3
 
4 4
 from oscar.core.loading import get_classes
5
-StockRecord, StockAlert = get_classes('partner.models', ('StockRecord', 'StockAlert'))
5
+StockRecord, StockAlert = get_classes('partner.models', ['StockRecord',
6
+                                                         'StockAlert'])
6 7
 
7 8
 
8 9
 @receiver(post_save, sender=StockRecord)

+ 4
- 3
oscar/apps/partner/strategy.py Datei anzeigen

@@ -62,7 +62,8 @@ class Base(object):
62 62
 
63 63
         - ``price``: a pricing policy object.
64 64
         - ``availability``: an availability policy object.
65
-        - ``stockrecord``: the stockrecord that is being used to calculate prices and
65
+        - ``stockrecord``: the stockrecord that is being used to calculate
66
+          prices and
66 67
 
67 68
         If a stockrecord is passed, return the appropriate ``StockInfo``
68 69
         instance for that product and stockrecord is returned.
@@ -179,8 +180,8 @@ class FixedRateTax(object):
179 180
     Pricing policy mixin for use with the ``Structured`` base strategy.
180 181
     This mixin applies a fixed rate tax to the base price from the product's
181 182
     stockrecord.
182
-    The price_incl_tax is quantized to two decimal places. Rounding behaviour is
183
-    Decimal's default
183
+    The price_incl_tax is quantized to two decimal places. Rounding behaviour
184
+    is Decimal's default
184 185
     """
185 186
     rate = D('0.20')
186 187
     exponent = D('0.01')

+ 36
- 19
oscar/apps/partner/utils.py Datei anzeigen

@@ -8,7 +8,8 @@ from oscar.apps.catalogue.categories import create_from_breadcrumbs
8 8
 from oscar.apps.dashboard.reports.csv_utils import CsvUnicodeReader
9 9
 from oscar.core.loading import get_class, get_classes
10 10
 ImportError = get_class('partner.exceptions', 'ImportError')
11
-Partner, StockRecord = get_classes('partner.models', ('Partner', 'StockRecord'))
11
+Partner, StockRecord = get_classes('partner.models', ['Partner',
12
+                                                      'StockRecord'])
12 13
 ProductClass, Product, Category, ProductCategory = get_classes(
13 14
     'catalogue.models', ('ProductClass', 'Product', 'Category',
14 15
                          'ProductCategory'))
@@ -23,9 +24,11 @@ class StockImporter(object):
23 24
         try:
24 25
             self._partner = Partner.objects.get(name=partner)
25 26
         except Partner.DoesNotExist:
26
-            name_list = ", ".join([d['name'] for d in Partner.objects.values('name')])
27
-            raise ImportError(_("Partner named '%(partner)s' does not exist (existing partners: %(list)s)") % {
28
-                              'partner': partner, 'list': name_list})
27
+            name_list = ", ".join([d['name']
28
+                                   for d in Partner.objects.values('name')])
29
+            raise ImportError(_("Partner named '%(partner)s' does not exist"
30
+                                " (existing partners: %(list)s)")
31
+                              % {'partner': partner, 'list': name_list})
29 32
 
30 33
     def handle(self, file_path=None):
31 34
         u"""Handles the actual import process"""
@@ -40,27 +43,35 @@ class StockImporter(object):
40 43
                  'unchanged_items': 0,
41 44
                  'unmatched_items': 0}
42 45
         row_number = 0
43
-        for row in CsvUnicodeReader(open(file_path, 'rb'), delimiter=self._delimiter, quotechar='"', escapechar='\\'):
46
+        for row in CsvUnicodeReader(open(file_path, 'rb'),
47
+                                    delimiter=self._delimiter, quotechar='"',
48
+                                    escapechar='\\'):
44 49
             row_number += 1
45 50
             self._import_row(row_number, row, stats)
46
-        msg = "\tUpdated items: %d\n\tUnchanged items: %d\n\tUnmatched items: %d" % (
47
-            stats['updated_items'],
48
-            stats['unchanged_items'],
49
-            stats['unmatched_items'])
51
+        msg = "\tUpdated items: %d\n\tUnchanged items: %d\n" \
52
+            "\tUnmatched items: %d" % (stats['updated_items'],
53
+                                       stats['unchanged_items'],
54
+                                       stats['unmatched_items'])
50 55
         self.logger.info(msg)
51 56
 
52 57
     def _import_row(self, row_number, row, stats):
53 58
         if len(row) != 3:
54
-            self.logger.error("Row number %d has an invalid number of fields, skipping..." % row_number)
59
+            self.logger.error("Row number %d has an invalid number of fields,"
60
+                              " skipping..." % row_number)
55 61
         else:
56
-            self._update_stockrecord(*row[:3], row_number=row_number, stats=stats)
62
+            self._update_stockrecord(*row[:3], row_number=row_number,
63
+                                     stats=stats)
57 64
 
58
-    def _update_stockrecord(self, partner_sku, price_excl_tax, num_in_stock, row_number, stats):
65
+    def _update_stockrecord(self, partner_sku, price_excl_tax, num_in_stock,
66
+                            row_number, stats):
59 67
         try:
60
-            stock = StockRecord.objects.get(partner=self._partner, partner_sku=partner_sku)
68
+            stock = StockRecord.objects.get(partner=self._partner,
69
+                                            partner_sku=partner_sku)
61 70
         except StockRecord.DoesNotExist:
62 71
             stats['unmatched_items'] += 1
63
-            self.logger.error("\t - Row %d: StockRecord for partner '%s' and sku '%s' does not exist, skipping..." % (row_number, self._partner, partner_sku))
72
+            self.logger.error("\t - Row %d: StockRecord for partner '%s' and"
73
+                              " sku '%s' does not exist, skipping..."
74
+                              % (row_number, self._partner, partner_sku))
64 75
             return
65 76
 
66 77
         price_changed = False
@@ -123,28 +134,34 @@ class CatalogueImporter(object):
123 134
         stats = {'new_items': 0,
124 135
                  'updated_items': 0}
125 136
         row_number = 0
126
-        for row in CsvUnicodeReader(open(file_path,'rb'), delimiter=self._delimiter, quotechar='"', escapechar='\\'):
137
+        for row in CsvUnicodeReader(open(file_path, 'rb'),
138
+                                    delimiter=self._delimiter, quotechar='"',
139
+                                    escapechar='\\'):
127 140
             row_number += 1
128 141
             self._import_row(row_number, row, stats)
129
-        msg = "New items: %d, updated items: %d" % (stats['new_items'], stats['updated_items'])
142
+        msg = "New items: %d, updated items: %d" % (stats['new_items'],
143
+                                                    stats['updated_items'])
130 144
         self.logger.info(msg)
131 145
 
132 146
     def _import_row(self, row_number, row, stats):
133 147
         if len(row) != 5 and len(row) != 9:
134
-            self.logger.error("Row number %d has an invalid number of fields (%d), skipping..." % (row_number, len(row)))
148
+            self.logger.error("Row number %d has an invalid number of fields"
149
+                              " (%d), skipping..." % (row_number, len(row)))
135 150
             return
136 151
         item = self._create_item(*row[:5], stats=stats)
137 152
         if len(row) == 9:
138 153
             # With stock data
139 154
             self._create_stockrecord(item, *row[5:9], stats=stats)
140 155
 
141
-    def _create_item(self, product_class, category_str, upc, title, description, stats):
156
+    def _create_item(self, product_class, category_str, upc, title,
157
+                     description, stats):
142 158
         # Ignore any entries that are NULL
143 159
         if description == 'NULL':
144 160
             description = ''
145 161
 
146 162
         # Create item class and item
147
-        product_class, __ = ProductClass.objects.get_or_create(name=product_class)
163
+        product_class, __ \
164
+            = ProductClass.objects.get_or_create(name=product_class)
148 165
         try:
149 166
             item = Product.objects.get(upc=upc)
150 167
             stats['updated_items'] += 1

+ 6
- 3
oscar/apps/partner/wrappers.py Datei anzeigen

@@ -21,7 +21,8 @@ class DefaultWrapper(object):
21 21
             return True
22 22
         return stockrecord.net_stock_level > 0
23 23
 
24
-    def is_purchase_permitted(self, stockrecord, user=None, quantity=1, product=None):
24
+    def is_purchase_permitted(self, stockrecord, user=None, quantity=1,
25
+                              product=None):
25 26
         """
26 27
         Test whether a particular purchase is possible (is a user buying a
27 28
         given quantity of the product)
@@ -56,7 +57,8 @@ class DefaultWrapper(object):
56 57
 
57 58
         This is normally used within CSS to add icons to stock messages
58 59
 
59
-        :param oscar.apps.partner.models.StockRecord stockrecord: stockrecord instance
60
+        :param oscar.apps.partner.models.StockRecord stockrecord: stockrecord
61
+        instance
60 62
         """
61 63
         if stockrecord.net_stock_level > 0:
62 64
             return self.CODE_IN_STOCK
@@ -68,7 +70,8 @@ class DefaultWrapper(object):
68 70
         """
69 71
         Return an availability message for the passed stockrecord.
70 72
 
71
-        :param oscar.apps.partner.models.StockRecord stockrecord: stockrecord instance
73
+        :param oscar.apps.partner.models.StockRecord stockrecord: stockrecord
74
+        instance
72 75
         """
73 76
         if stockrecord.net_stock_level > 0:
74 77
             return _("In stock (%d available)") % stockrecord.net_stock_level

+ 9
- 10
oscar/apps/payment/exceptions.py Datei anzeigen

@@ -16,12 +16,11 @@ class InvalidGatewayRequestError(PaymentError):
16 16
 
17 17
 class InsufficientPaymentSources(PaymentError):
18 18
     """
19
-    Exception for when a user attempts to checkout without
20
-    specifying enough payment sources to cover the entire order 
21
-    total. 
22
-    
23
-    Eg. When selecting an allocation off a giftcard but not specifying
24
-        a bankcard to take the remainder from.
19
+    Exception for when a user attempts to checkout without specifying enough
20
+    payment sources to cover the entire order total.
21
+
22
+    Eg. When selecting an allocation off a giftcard but not specifying a
23
+    bankcard to take the remainder from.
25 24
     """
26 25
     pass
27 26
 
@@ -30,15 +29,15 @@ class RedirectRequired(PaymentError):
30 29
     """
31 30
     Exception to be used when payment processsing requires a redirect
32 31
     """
33
-    
32
+
34 33
     def __init__(self, url):
35 34
         self.url = url
36 35
 
37 36
 
38 37
 class UnableToTakePayment(PaymentError):
39 38
     """
40
-    Exception to be used for ANTICIPATED payment errors (eg card number wrong, expiry date
41
-    has passed).  The message passed here will be shown to the end user.
39
+    Exception to be used for ANTICIPATED payment errors (eg card number wrong,
40
+    expiry date has passed).  The message passed here will be shown to the end
41
+    user.
42 42
     """
43 43
     pass
44
-    

+ 12
- 8
oscar/apps/promotions/admin.py Datei anzeigen

@@ -1,25 +1,31 @@
1 1
 from django.contrib import admin
2 2
 
3
-from oscar.apps.promotions.models import Image, MultiImage, RawHTML, HandPickedProductList, OrderedProduct, AutomaticProductList, TabbedBlock, \
4
-                                  PagePromotion, KeywordPromotion, SingleProduct
3
+from oscar.apps.promotions.models import Image, MultiImage, RawHTML, \
4
+    HandPickedProductList, OrderedProduct, AutomaticProductList, TabbedBlock, \
5
+    PagePromotion, KeywordPromotion, SingleProduct
5 6
 
6 7
 
7 8
 class OrderProductInline(admin.TabularInline):
8 9
     model = OrderedProduct
9
-    
10
+
11
+
10 12
 class HandPickedProductListAdmin(admin.ModelAdmin):
11 13
     inlines = [OrderProductInline]
12 14
 
15
+
13 16
 class PagePromotionAdmin(admin.ModelAdmin):
14 17
     list_display = ['page_url', 'content_object', 'position']
15 18
     exclude = ['clicks']
16
-    
19
+
17 20
     def get_form(self, request, obj=None, **kwargs):
18
-        form = super(PagePromotionAdmin,self).get_form(request, obj, **kwargs)
21
+        form = super(PagePromotionAdmin, self).get_form(request, obj, **kwargs)
19 22
         # Only allow links to models within the promotions app
20
-        form.base_fields['content_type'].queryset = form.base_fields['content_type'].queryset.filter(app_label='promotions')
23
+        form.base_fields['content_type'].queryset \
24
+            = form.base_fields['content_type'].queryset\
25
+            .filter(app_label='promotions')
21 26
         return form
22 27
 
28
+
23 29
 class KeywordPromotionAdmin(admin.ModelAdmin):
24 30
     list_display = ['keyword', 'position', 'clicks']
25 31
     readonly_fields = ['clicks']
@@ -34,5 +40,3 @@ admin.site.register(TabbedBlock)
34 40
 admin.site.register(PagePromotion, PagePromotionAdmin)
35 41
 admin.site.register(KeywordPromotion, KeywordPromotionAdmin)
36 42
 admin.site.register(SingleProduct)
37
-
38
-

+ 0
- 0
oscar/apps/promotions/app.py Datei anzeigen


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.

Laden…
Abbrechen
Speichern