David Winterbottom 13 роки тому
джерело
коміт
0555e703e3
3 змінених файлів з 110 додано та 61 видалено
  1. 1
    1
      Makefile
  2. 82
    33
      oscar/apps/basket/views.py
  3. 27
    27
      oscar/apps/payment/models.py

+ 1
- 1
Makefile Переглянути файл

@@ -22,7 +22,7 @@ ci:
22 22
 	pip install -r requirements.txt
23 23
 	./runtests.py --with-coverage --with-xunit
24 24
 	coverage xml
25
-	flake8 --ignore=W292 oscar | perl -ple "s/: /: [E] /" | grep -v migrations > violations.txt
25
+	flake8 --ignore=W292,E202 oscar | perl -ple "s/: /: [E] /" | grep -v migrations > violations.txt
26 26
 
27 27
 test:
28 28
 	./runtests.py

+ 82
- 33
oscar/apps/basket/views.py Переглянути файл

@@ -30,7 +30,8 @@ class BasketView(ModelFormSetView):
30 30
         return self.request.basket.all_lines()
31 31
 
32 32
     def get_default_shipping_method(self, basket):
33
-        return Repository().get_default_shipping_method(self.request.user, self.request.basket)
33
+        return Repository().get_default_shipping_method(
34
+            self.request.user, self.request.basket)
34 35
 
35 36
     def get_basket_warnings(self, basket):
36 37
         """
@@ -61,18 +62,24 @@ class BasketView(ModelFormSetView):
61 62
         method = self.get_default_shipping_method(self.request.basket)
62 63
         context['shipping_method'] = method
63 64
         context['shipping_charge_incl_tax'] = method.basket_charge_incl_tax()
64
-        context['order_total_incl_tax'] = self.request.basket.total_incl_tax + method.basket_charge_incl_tax()
65
-        context['basket_warnings'] = self.get_basket_warnings(self.request.basket)
66
-        context['upsell_messages'] = self.get_upsell_messages(self.request.basket)
65
+        context['order_total_incl_tax'] = (
66
+            self.request.basket.total_incl_tax +
67
+            method.basket_charge_incl_tax())
68
+        context['basket_warnings'] = self.get_basket_warnings(
69
+            self.request.basket)
70
+        context['upsell_messages'] = self.get_upsell_messages(
71
+            self.request.basket)
67 72
 
68 73
         if self.request.user.is_authenticated():
69 74
             try:
70
-                saved_basket = self.basket_model.saved.get(owner=self.request.user)
75
+                saved_basket = self.basket_model.saved.get(
76
+                    owner=self.request.user)
71 77
             except self.basket_model.DoesNotExist:
72 78
                 pass
73 79
             else:
74 80
                 if not saved_basket.is_empty:
75
-                    saved_queryset = saved_basket.all_lines().select_related('product', 'product__stockrecord')
81
+                    saved_queryset = saved_basket.all_lines().select_related(
82
+                        'product', 'product__stockrecord')
76 83
                     formset = SavedLineFormSet(user=self.request.user,
77 84
                                                basket=self.request.basket,
78 85
                                                queryset=saved_queryset,
@@ -87,14 +94,20 @@ class BasketView(ModelFormSetView):
87 94
     def formset_valid(self, formset):
88 95
         save_for_later = False
89 96
         for form in formset:
90
-            if hasattr(form, 'cleaned_data') and form.cleaned_data['save_for_later']:
97
+            if (hasattr(form, 'cleaned_data') and
98
+                form.cleaned_data['save_for_later']):
91 99
                 line = form.instance
92 100
                 if self.request.user.is_authenticated():
93 101
                     self.move_line_to_saved_basket(line)
94
-                    messages.info(self.request, _(u"'%(title)s' has been saved for later") % {'title': line.product})
102
+                    messages.info(
103
+                        self.request,
104
+                        _(u"'%(title)s' has been saved for later") % {
105
+                            'title': line.product})
95 106
                     save_for_later = True
96 107
                 else:
97
-                    messages.error(self.request, _("You can't save an item for later if you're not logged in!"))
108
+                    messages.error(
109
+                        self.request,
110
+                        _("You can't save an item for later if you're not logged in!"))
98 111
                     return HttpResponseRedirect(self.get_success_url())
99 112
 
100 113
         if save_for_later:
@@ -103,14 +116,17 @@ class BasketView(ModelFormSetView):
103 116
         return super(BasketView, self).formset_valid(formset)
104 117
 
105 118
     def move_line_to_saved_basket(self, line):
106
-        saved_basket, _ = get_model('basket', 'basket').saved.get_or_create(owner=self.request.user)
119
+        saved_basket, _ = get_model('basket', 'basket').saved.get_or_create(
120
+            owner=self.request.user)
107 121
         saved_basket.merge_line(line)
108 122
 
109 123
     def formset_invalid(self, formset):
110 124
         errors = []
111 125
         for error_dict in formset.errors:
112
-            errors += [error_list.as_text() for error_list in error_dict.values()]
113
-        msg = _("Your basket couldn't be updated because:\n%s") % "\n".join(errors)
126
+            errors += [error_list.as_text()
127
+                       for error_list in error_dict.values()]
128
+        msg = _("Your basket couldn't be updated because:\n%s") % (
129
+            "\n".join(errors),)
114 130
         messages.warning(self.request, msg)
115 131
         return super(BasketView, self).formset_invalid(formset)
116 132
 
@@ -160,12 +176,16 @@ class BasketAddView(FormView):
160 176
         options = []
161 177
         for option in form.instance.options:
162 178
             if option.code in form.cleaned_data:
163
-                options.append({'option': option, 'value': form.cleaned_data[option.code]})
164
-        self.request.basket.add_product(form.instance, form.cleaned_data['quantity'], options)
179
+                options.append({
180
+                    'option': option,
181
+                    'value': form.cleaned_data[option.code]})
182
+        self.request.basket.add_product(
183
+            form.instance, form.cleaned_data['quantity'], options)
165 184
         messages.success(self.request, self.get_success_message(form))
166 185
 
167 186
         # Send signal for basket addition
168
-        self.add_signal.send(sender=self, product=form.instance, user=self.request.user)
187
+        self.add_signal.send(
188
+            sender=self, product=form.instance, user=self.request.user)
169 189
 
170 190
         return super(BasketAddView, self).form_valid(form)
171 191
 
@@ -173,17 +193,20 @@ class BasketAddView(FormView):
173 193
         qty = form.cleaned_data['quantity']
174 194
         title = form.instance.get_title()
175 195
         if qty == 1:
176
-            return _("'%(title)s' has been added to your basket") % {'title': title}
196
+            return _("'%(title)s' has been added to your basket") % {
197
+                'title': title}
177 198
         else:
178
-            return _("'%(title)s' (quantity %(quantity)d) has been added to your"
179
-                     "basket") % {'title': title, 'quantity': qty}
199
+            return _(
200
+                "'%(title)s' (quantity %(quantity)d) has been added to your"
201
+                "basket") % {'title': title, 'quantity': qty}
180 202
 
181 203
     def form_invalid(self, form):
182 204
         msgs = []
183 205
         for error in form.errors.values():
184 206
             msgs.append(error.as_text())
185 207
         messages.error(self.request, ",".join(msgs))
186
-        return HttpResponseRedirect(self.request.META.get('HTTP_REFERER',reverse('basket:summary')))
208
+        return HttpResponseRedirect(
209
+            self.request.META.get('HTTP_REFERER', reverse('basket:summary')))
187 210
 
188 211
 
189 212
 class VoucherAddView(FormView):
@@ -196,7 +219,10 @@ class VoucherAddView(FormView):
196 219
 
197 220
     def apply_voucher_to_basket(self, voucher):
198 221
         if not voucher.is_active():
199
-            messages.error(self.request, _("The '%(code)s' voucher has expired") % {'code': voucher.code})
222
+            messages.error(
223
+                self.request,
224
+                _("The '%(code)s' voucher has expired") % {
225
+                    'code': voucher.code})
200 226
             return
201 227
 
202 228
         is_available, message = voucher.is_available_to_user(self.request.user)
@@ -223,29 +249,43 @@ class VoucherAddView(FormView):
223 249
                 found_discount = True
224 250
                 break
225 251
         if not found_discount:
226
-            messages.warning(self.request, _("Your basket does not qualify for a voucher discount"))
252
+            messages.warning(
253
+                self.request,
254
+                _("Your basket does not qualify for a voucher discount"))
227 255
             self.request.basket.vouchers.remove(voucher)
228 256
         else:
229
-            messages.info(self.request, _("Voucher '%(code)s' added to basket") % {'code': voucher.code})
257
+            messages.info(
258
+                self.request,
259
+                _("Voucher '%(code)s' added to basket") % {
260
+                    'code': voucher.code})
230 261
 
231 262
     def form_valid(self, form):
232 263
         code = form.cleaned_data['code']
233 264
         if not self.request.basket.id:
234
-            return HttpResponseRedirect(self.request.META.get('HTTP_REFERER', reverse('basket:summary')))
265
+            return HttpResponseRedirect(
266
+                self.request.META.get('HTTP_REFERER',
267
+                                      reverse('basket:summary')))
235 268
         if self.request.basket.contains_voucher(code):
236
-            messages.error(self.request, _("You have already added the '%(code)s' voucher to your basket") % {'code': code})
269
+            messages.error(
270
+                self.request,
271
+                _("You have already added the '%(code)s' voucher to "
272
+                  "your basket") % {'code': code})
237 273
         else:
238 274
             try:
239 275
                 voucher = self.voucher_model._default_manager.get(code=code)
240 276
             except self.voucher_model.DoesNotExist:
241
-                messages.error(self.request, _("No voucher found with code '%(code)s'") % {'code': code})
277
+                messages.error(
278
+                    self.request,
279
+                    _("No voucher found with code '%(code)s'") % {
280
+                        'code': code})
242 281
             else:
243 282
                 self.apply_voucher_to_basket(voucher)
244
-        return HttpResponseRedirect(self.request.META.get('HTTP_REFERER', reverse('basket:summary')))
283
+        return HttpResponseRedirect(
284
+            self.request.META.get('HTTP_REFERER', reverse('basket:summary')))
245 285
 
246 286
     def form_invalid(self, form):
247 287
         messages.error(self.request, _("Please enter a voucher code"))
248
-        return HttpResponseRedirect(reverse('basket:summary')+'#voucher')
288
+        return HttpResponseRedirect(reverse('basket:summary') + '#voucher')
249 289
 
250 290
 
251 291
 class VoucherRemoveView(View):
@@ -263,11 +303,13 @@ class VoucherRemoveView(View):
263 303
         try:
264 304
             voucher = request.basket.vouchers.get(id=voucher_id)
265 305
         except ObjectDoesNotExist:
266
-            messages.error(request, _("No voucher found with id '%d'") % voucher_id)
306
+            messages.error(
307
+                request, _("No voucher found with id '%d'") % voucher_id)
267 308
         else:
268 309
             request.basket.vouchers.remove(voucher)
269 310
             request.basket.save()
270
-            messages.info(request, _("Voucher '%s' removed from basket") % voucher.code)
311
+            messages.info(
312
+                request, _("Voucher '%s' removed from basket") % voucher.code)
271 313
         return HttpResponseRedirect(reverse('basket:summary'))
272 314
 
273 315
 
@@ -285,7 +327,8 @@ class SavedView(ModelFormSetView):
285 327
     def get_queryset(self):
286 328
         try:
287 329
             saved_basket = self.basket_model.saved.get(owner=self.request.user)
288
-            return saved_basket.all_lines().select_related('product', 'product__stockrecord')
330
+            return saved_basket.all_lines().select_related(
331
+                'product', 'product__stockrecord')
289 332
         except self.basket_model.DoesNotExist:
290 333
             return []
291 334
 
@@ -304,7 +347,8 @@ class SavedView(ModelFormSetView):
304 347
         for form in formset:
305 348
             if form.cleaned_data['move_to_basket']:
306 349
                 is_move = True
307
-                msg = _("'%s' has been moved back to your basket") % form.instance.product
350
+                msg = _("'%(product)s' has been moved back to your basket") % {
351
+                    'product': form.instance.product}
308 352
                 messages.info(self.request, msg)
309 353
                 real_basket = self.request.basket
310 354
                 real_basket.merge_line(form.instance)
@@ -314,5 +358,10 @@ class SavedView(ModelFormSetView):
314 358
         return super(SavedView, self).formset_valid(formset)
315 359
 
316 360
     def formset_invalid(self, formset):
317
-        messages.error(self.request, '\n'.join(error for ed in formset.errors for el in ed.values() for error in el))
318
-        return HttpResponseRedirect(self.request.META.get('HTTP_REFERER', reverse('basket:summary')))
361
+        messages.error(
362
+            self.request,
363
+            '\n'.join(
364
+                error for ed in formset.errors for el
365
+                in ed.values() for error in el))
366
+        return HttpResponseRedirect(
367
+            self.request.META.get('HTTP_REFERER', reverse('basket:summary')))

+ 27
- 27
oscar/apps/payment/models.py Переглянути файл

@@ -9,12 +9,12 @@ from django.conf import settings
9 9
 class Transaction(models.Model):
10 10
     """
11 11
     A transaction for payment sources which need a secondary 'transaction' to actually take the money
12
-    
12
+
13 13
     This applies mainly to credit card sources which can be a pre-auth for the money.  A 'complete'
14 14
     needs to be run later to debit the money from the account.
15 15
     """
16 16
     source = models.ForeignKey('payment.Source', related_name='transactions', verbose_name=_("Source"))
17
-    
17
+
18 18
     # We define some sample types
19 19
     AUTHORISE, DEBIT, REFUND = 'Authorise', 'Debit', 'Refund'
20 20
     txn_type = models.CharField(_("Type"), max_length=128, blank=True)
@@ -22,7 +22,7 @@ class Transaction(models.Model):
22 22
     reference = models.CharField(_("Reference"), max_length=128, null=True)
23 23
     status = models.CharField(_("Status"), max_length=128, null=True)
24 24
     date_created = models.DateTimeField(_("Date Created"), auto_now_add=True)
25
-    
25
+
26 26
     def __unicode__(self):
27 27
         return _("%(type)s of %(amount).2f") % {'type': self.txn_type, 'amount': self.amount}
28 28
 
@@ -33,8 +33,8 @@ class Transaction(models.Model):
33 33
 
34 34
 class Source(models.Model):
35 35
     """
36
-    A source of payment for an order.  
37
-    
36
+    A source of payment for an order.
37
+
38 38
     This is normally a credit card which has been pre-authed for the order
39 39
     amount, but some applications will allow orders to be paid for using
40 40
     multiple sources such as cheque, credit accounts, gift cards.  Each payment
@@ -43,24 +43,24 @@ class Source(models.Model):
43 43
     order = models.ForeignKey('order.Order', related_name='sources', verbose_name=_("Order"))
44 44
     source_type = models.ForeignKey('payment.SourceType', verbose_name=_("Source Type"))
45 45
     currency = models.CharField(_("Currency"), max_length=12, default=settings.OSCAR_DEFAULT_CURRENCY)
46
-    
46
+
47 47
     # Track the various amounts associated with this source
48 48
     amount_allocated = models.DecimalField(_("Amount Allocated"), decimal_places=2, max_digits=12, default=Decimal('0.00'))
49 49
     amount_debited = models.DecimalField(_("Amount Debited"), decimal_places=2, max_digits=12, default=Decimal('0.00'))
50 50
     amount_refunded = models.DecimalField(_("Amount Refunded"), decimal_places=2, max_digits=12, default=Decimal('0.00'))
51
-    
51
+
52 52
     # Reference number for this payment source.  This is often used to look up a
53
-    # transaction model for a particular payment partner. 
53
+    # transaction model for a particular payment partner.
54 54
     reference = models.CharField(_("Reference"), max_length=128, blank=True, null=True)
55
-    
55
+
56 56
     # A customer-friendly label for the source, eg XXXX-XXXX-XXXX-1234
57 57
     label = models.CharField(_("Label"), max_length=128, blank=True, null=True)
58
-    
58
+
59 59
     # A dictionary of submission data that is stored as part of the
60 60
     # checkout process.
61 61
     submission_data = None
62
-    
63
-    # We keep a list of deferred transactions that are only actually saved when 
62
+
63
+    # We keep a list of deferred transactions that are only actually saved when
64 64
     # the source is saved for the first time
65 65
     deferred_txns = None
66 66
 
@@ -74,16 +74,16 @@ class Source(models.Model):
74 74
         if self.reference:
75 75
             description += _(" (reference: %s)") % self.reference
76 76
         return description
77
-    
77
+
78 78
     def save(self, *args, **kwargs):
79 79
         super(Source, self).save(*args, **kwargs)
80 80
         if self.deferred_txns:
81 81
             for txn in self.deferred_txns:
82 82
                 self._create_transaction(*txn)
83
-    
83
+
84 84
     def balance(self):
85 85
         return self.amount_allocated - self.amount_debited + self.amount_refunded
86
-    
86
+
87 87
     def create_deferred_transaction(self, txn_type, amount, reference=None, status=None):
88 88
         """
89 89
         Register the data for a transaction that can't be created yet due to FK
@@ -93,14 +93,14 @@ class Source(models.Model):
93 93
         if self.deferred_txns is None:
94 94
             self.deferred_txns = []
95 95
         self.deferred_txns.append((txn_type, amount, reference, status))
96
-    
96
+
97 97
     def _create_transaction(self, txn_type, amount, reference=None, status=None):
98 98
         Transaction.objects.create(source=self,
99 99
                                    txn_type=txn_type,
100 100
                                    amount=amount,
101 101
                                    reference=reference,
102 102
                                    status=status)
103
-    
103
+
104 104
     def allocate(self, amount, reference=None, status=None):
105 105
         """
106 106
         Convenience method for ring-fencing money against this source
@@ -108,7 +108,7 @@ class Source(models.Model):
108 108
         self.amount_allocated += amount
109 109
         self.save()
110 110
         self._create_transaction(Transaction.AUTHORISE, amount, reference, status)
111
-    
111
+
112 112
     def debit(self, amount=None, reference=None, status=None):
113 113
         """
114 114
         Convenience method for recording debits against this source
@@ -118,7 +118,7 @@ class Source(models.Model):
118 118
         self.amount_debited += amount
119 119
         self.save()
120 120
         self._create_transaction(Transaction.DEBIT, amount, reference, status)
121
-        
121
+
122 122
     def refund(self, amount, reference=None, status=None):
123 123
         """
124 124
         Convenience method for recording refunds against this source
@@ -126,19 +126,19 @@ class Source(models.Model):
126 126
         self.amount_refunded += amount
127 127
         self.save()
128 128
         self._create_transaction(Transaction.REFUND, amount, reference, status)
129
-    
129
+
130 130
     @property
131 131
     def amount_available_for_refund(self):
132 132
         """
133 133
         Return the amount available to be refunded
134 134
         """
135 135
         return self.amount_debited - self.amount_refunded
136
-    
137
-    
136
+
137
+
138 138
 class SourceType(models.Model):
139 139
     """
140 140
     A type of payment source.
141
-    
141
+
142 142
     This could be an external partner like PayPal or DataCash,
143 143
     or an internal source such as a managed account.i
144 144
     """
@@ -157,7 +157,7 @@ class SourceType(models.Model):
157 157
         if not self.code:
158 158
             self.code = slugify(self.name)
159 159
         super(SourceType, self).save(*args, **kwargs)
160
-    
160
+
161 161
 
162 162
 class Bankcard(models.Model):
163 163
     user = models.ForeignKey('auth.User', related_name='bankcards', verbose_name=_("User"))
@@ -165,7 +165,7 @@ class Bankcard(models.Model):
165 165
     name = models.CharField(_("Name"), max_length=255)
166 166
     number = models.CharField(_("Number"), max_length=32)
167 167
     expiry_date = models.DateField(_("Expiry Date"))
168
-    
168
+
169 169
     # For payment partners who are storing the full card details for us
170 170
     partner_reference = models.CharField(_("Partner Reference"), max_length=255, null=True, blank=True)
171 171
 
@@ -175,7 +175,7 @@ class Bankcard(models.Model):
175 175
 
176 176
     def save(self, *args, **kwargs):
177 177
         self.number = self._get_obfuscated_number()
178
-        super(Bankcard, self).save(*args, **kwargs)    
179
-        
178
+        super(Bankcard, self).save(*args, **kwargs)
179
+
180 180
     def _get_obfuscated_number(self):
181 181
         return u"XXXX-XXXX-XXXX-%s" % self.number[-4:]

Завантаження…
Відмінити
Зберегти