Просмотр исходного кода

Add alters_data attribute to all model functions that alter data

master
David Winterbottom 13 лет назад
Родитель
Сommit
d0f19852da

+ 6
- 0
oscar/apps/basket/abstract_models.py Просмотреть файл

@@ -150,6 +150,7 @@ class AbstractBasket(models.Model):
150 150
             line.quantity += quantity
151 151
             line.save()
152 152
         self._lines = None
153
+    add_product.alters_data = True
153 154
 
154 155
     def get_discounts(self):
155 156
         if self.discounts is None:
@@ -193,6 +194,7 @@ class AbstractBasket(models.Model):
193 194
                                              line.quantity)
194 195
             existing_line.save()
195 196
             line.delete()
197
+    merge_line.alters_data = True
196 198
 
197 199
     def merge(self, basket, add_quantities=True):
198 200
         """
@@ -207,6 +209,7 @@ class AbstractBasket(models.Model):
207 209
         basket.date_merged = now()
208 210
         basket.save()
209 211
         self._lines = None
212
+    merge.alters_data = True
210 213
 
211 214
     def freeze(self):
212 215
         """
@@ -214,6 +217,7 @@ class AbstractBasket(models.Model):
214 217
         """
215 218
         self.status = self.FROZEN
216 219
         self.save()
220
+    freeze.alters_data = True
217 221
 
218 222
     def thaw(self):
219 223
         """
@@ -221,12 +225,14 @@ class AbstractBasket(models.Model):
221 225
         """
222 226
         self.status = self.OPEN
223 227
         self.save()
228
+    thaw.alters_data = True
224 229
 
225 230
     def set_as_submitted(self):
226 231
         """Mark this basket as submitted."""
227 232
         self.status = self.SUBMITTED
228 233
         self.date_submitted = now()
229 234
         self.save()
235
+    set_as_submitted.alters_data = True
230 236
 
231 237
     def set_as_tax_exempt(self):
232 238
         self.exempt_from_tax = True

+ 3
- 1
oscar/apps/catalogue/abstract_models.py Просмотреть файл

@@ -375,8 +375,10 @@ class AbstractProduct(models.Model):
375 375
         from oscar.apps.catalogue.categories import create_from_breadcrumbs
376 376
         category = create_from_breadcrumbs(breadcrumb)
377 377
 
378
-        temp = get_model('catalogue', 'ProductCategory')(category=category, product=self)
378
+        temp = get_model('catalogue', 'ProductCategory')(
379
+            category=category, product=self)
379 380
         temp.save()
381
+    add_category_from_breadcrumbs.alters_data = True
380 382
 
381 383
     def attribute_summary(self):
382 384
         u"""Return a string of all of a product's attributes"""

+ 4
- 0
oscar/apps/customer/abstract_models.py Просмотреть файл

@@ -158,6 +158,7 @@ class AbstractNotification(models.Model):
158 158
     def archive(self):
159 159
         self.location = self.ARCHIVE
160 160
         self.save()
161
+    archive.alters_data = True
161 162
 
162 163
     @property
163 164
     def is_read(self):
@@ -231,16 +232,19 @@ class AbstractProductAlert(models.Model):
231 232
         self.status = self.ACTIVE
232 233
         self.date_confirmed = now()
233 234
         self.save()
235
+    confirm.alters_data = True
234 236
 
235 237
     def cancel(self):
236 238
         self.status = self.CANCELLED
237 239
         self.date_cancelled = now()
238 240
         self.save()
241
+    cancel.alters_data = True
239 242
 
240 243
     def close(self):
241 244
         self.status = self.CLOSED
242 245
         self.date_closed = now()
243 246
         self.save()
247
+    close.alters_data = True
244 248
 
245 249
     def get_email_address(self):
246 250
         if self.user:

+ 1
- 0
oscar/apps/offer/models.py Просмотреть файл

@@ -174,6 +174,7 @@ class ConditionalOffer(models.Model):
174 174
         self.num_orders += 1
175 175
         self.total_discount += discount
176 176
         self.save()
177
+    record_usage.alters_data = True
177 178
 
178 179
 
179 180
 class Condition(models.Model):

+ 2
- 0
oscar/apps/order/abstract_models.py Просмотреть файл

@@ -78,6 +78,7 @@ class AbstractOrder(models.Model):
78 78
                 line.status = self.cascade[self.status]
79 79
                 line.save()
80 80
         self.save()
81
+    set_status.alters_data = True
81 82
 
82 83
     @property
83 84
     def is_anonymous(self):
@@ -340,6 +341,7 @@ class AbstractLine(models.Model):
340 341
                                     'new_status': new_status, 'status': self.status})
341 342
         self.status = new_status
342 343
         self.save()
344
+    set_status.alters_data = True
343 345
 
344 346
     @property
345 347
     def category(self):

+ 5
- 0
oscar/apps/partner/abstract_models.py Просмотреть файл

@@ -123,6 +123,7 @@ class AbstractStockRecord(models.Model):
123 123
             self.num_allocated = 0
124 124
         self.num_allocated += quantity
125 125
         self.save()
126
+    allocate.alters_data = True
126 127
 
127 128
     def is_allocation_consumption_possible(self, quantity):
128 129
         return quantity <= min(self.num_allocated, self.num_in_stock)
@@ -139,12 +140,14 @@ class AbstractStockRecord(models.Model):
139 140
         self.num_allocated -= quantity
140 141
         self.num_in_stock -= quantity
141 142
         self.save()
143
+    consume_allocation.alters_data = True
142 144
 
143 145
     def cancel_allocation(self, quantity):
144 146
         # We ignore requests that request a cancellation of more than the amount already
145 147
         # allocated.
146 148
         self.num_allocated -= min(self.num_allocated, quantity)
147 149
         self.save()
150
+    cancel_allocation.alters_data = True
148 151
 
149 152
     @property
150 153
     def net_stock_level(self):
@@ -169,6 +172,7 @@ class AbstractStockRecord(models.Model):
169 172
         """
170 173
         self.price_excl_tax = price
171 174
         self.save()
175
+    set_discount_price.alters_data = True
172 176
 
173 177
     # Price retrieval methods - these default to no tax being applicable
174 178
     # These are intended to be overridden.
@@ -271,6 +275,7 @@ class AbstractStockAlert(models.Model):
271 275
     def close(self):
272 276
         self.status = self.CLOSED
273 277
         self.save()
278
+    close.alters_data = True
274 279
 
275 280
     def __unicode__(self):
276 281
         return _('<stockalert for "%(stock)s" status %(status)s>') % {'stock': self.stockrecord, 'status': self.status}

+ 49
- 25
oscar/apps/payment/models.py Просмотреть файл

@@ -8,12 +8,16 @@ from django.conf import settings
8 8
 
9 9
 class Transaction(models.Model):
10 10
     """
11
-    A transaction for payment sources which need a secondary 'transaction' to actually take the money
11
+    A transaction for payment sources which need a secondary 'transaction' to
12
+    actually take the money
12 13
 
13
-    This applies mainly to credit card sources which can be a pre-auth for the money.  A 'complete'
14
-    needs to be run later to debit the money from the account.
14
+    This applies mainly to credit card sources which can be a pre-auth for the
15
+    money.  A 'complete' needs to be run later to debit the money from the
16
+    account.
15 17
     """
16
-    source = models.ForeignKey('payment.Source', related_name='transactions', verbose_name=_("Source"))
18
+    source = models.ForeignKey(
19
+        'payment.Source', related_name='transactions',
20
+        verbose_name=_("Source"))
17 21
 
18 22
     # We define some sample types
19 23
     AUTHORISE, DEBIT, REFUND = 'Authorise', 'Debit', 'Refund'
@@ -24,7 +28,8 @@ class Transaction(models.Model):
24 28
     date_created = models.DateTimeField(_("Date Created"), auto_now_add=True)
25 29
 
26 30
     def __unicode__(self):
27
-        return _("%(type)s of %(amount).2f") % {'type': self.txn_type, 'amount': self.amount}
31
+        return _("%(type)s of %(amount).2f") % {
32
+            'type': self.txn_type, 'amount': self.amount}
28 33
 
29 34
     class Meta:
30 35
         verbose_name = _("Transaction")
@@ -40,18 +45,28 @@ class Source(models.Model):
40 45
     multiple sources such as cheque, credit accounts, gift cards.  Each payment
41 46
     source will have its own entry.
42 47
     """
43
-    order = models.ForeignKey('order.Order', related_name='sources', verbose_name=_("Order"))
44
-    source_type = models.ForeignKey('payment.SourceType', verbose_name=_("Source Type"))
45
-    currency = models.CharField(_("Currency"), max_length=12, default=settings.OSCAR_DEFAULT_CURRENCY)
48
+    order = models.ForeignKey('order.Order',
49
+                              related_name='sources', verbose_name=_("Order"))
50
+    source_type = models.ForeignKey('payment.SourceType',
51
+                                    verbose_name=_("Source Type"))
52
+    currency = models.CharField(_("Currency"), max_length=12,
53
+                                default=settings.OSCAR_DEFAULT_CURRENCY)
46 54
 
47 55
     # Track the various amounts associated with this source
48
-    amount_allocated = models.DecimalField(_("Amount Allocated"), decimal_places=2, max_digits=12, default=Decimal('0.00'))
49
-    amount_debited = models.DecimalField(_("Amount Debited"), decimal_places=2, max_digits=12, default=Decimal('0.00'))
50
-    amount_refunded = models.DecimalField(_("Amount Refunded"), decimal_places=2, max_digits=12, default=Decimal('0.00'))
51
-
52
-    # Reference number for this payment source.  This is often used to look up a
53
-    # transaction model for a particular payment partner.
54
-    reference = models.CharField(_("Reference"), max_length=128, blank=True, null=True)
56
+    amount_allocated = models.DecimalField(
57
+        _("Amount Allocated"), decimal_places=2, max_digits=12,
58
+        default=Decimal('0.00'))
59
+    amount_debited = models.DecimalField(
60
+        _("Amount Debited"), decimal_places=2, max_digits=12,
61
+        default=Decimal('0.00'))
62
+    amount_refunded = models.DecimalField(
63
+        _("Amount Refunded"), decimal_places=2, max_digits=12,
64
+        default=Decimal('0.00'))
65
+
66
+    # Reference number for this payment source.  This is often used to look up
67
+    # a transaction model for a particular payment partner.
68
+    reference = models.CharField(_("Reference"), max_length=128,
69
+                                 blank=True, null=True)
55 70
 
56 71
     # A customer-friendly label for the source, eg XXXX-XXXX-XXXX-1234
57 72
     label = models.CharField(_("Label"), max_length=128, blank=True, null=True)
@@ -82,19 +97,22 @@ class Source(models.Model):
82 97
                 self._create_transaction(*txn)
83 98
 
84 99
     def balance(self):
85
-        return self.amount_allocated - self.amount_debited + self.amount_refunded
100
+        return (self.amount_allocated - self.amount_debited +
101
+                self.amount_refunded)
86 102
 
87
-    def create_deferred_transaction(self, txn_type, amount, reference=None, status=None):
103
+    def create_deferred_transaction(self, txn_type, amount, reference=None,
104
+                                    status=None):
88 105
         """
89 106
         Register the data for a transaction that can't be created yet due to FK
90
-        constraints.  This happens at checkout where create an payment source and a
91
-        transaction but can't save them until the order model exists.
107
+        constraints.  This happens at checkout where create an payment source
108
+        and a transaction but can't save them until the order model exists.
92 109
         """
93 110
         if self.deferred_txns is None:
94 111
             self.deferred_txns = []
95 112
         self.deferred_txns.append((txn_type, amount, reference, status))
96 113
 
97
-    def _create_transaction(self, txn_type, amount, reference=None, status=None):
114
+    def _create_transaction(self, txn_type, amount, reference=None,
115
+                            status=None):
98 116
         Transaction.objects.create(source=self,
99 117
                                    txn_type=txn_type,
100 118
                                    amount=amount,
@@ -107,7 +125,9 @@ class Source(models.Model):
107 125
         """
108 126
         self.amount_allocated += amount
109 127
         self.save()
110
-        self._create_transaction(Transaction.AUTHORISE, amount, reference, status)
128
+        self._create_transaction(
129
+            Transaction.AUTHORISE, amount, reference, status)
130
+    allocate.alters_data = True
111 131
 
112 132
     def debit(self, amount=None, reference=None, status=None):
113 133
         """
@@ -118,6 +138,7 @@ class Source(models.Model):
118 138
         self.amount_debited += amount
119 139
         self.save()
120 140
         self._create_transaction(Transaction.DEBIT, amount, reference, status)
141
+    debit.alters_data = True
121 142
 
122 143
     def refund(self, amount, reference=None, status=None):
123 144
         """
@@ -126,6 +147,7 @@ class Source(models.Model):
126 147
         self.amount_refunded += amount
127 148
         self.save()
128 149
         self._create_transaction(Transaction.REFUND, amount, reference, status)
150
+    refund.alters_data = True
129 151
 
130 152
     @property
131 153
     def amount_available_for_refund(self):
@@ -143,8 +165,8 @@ class SourceType(models.Model):
143 165
     or an internal source such as a managed account.i
144 166
     """
145 167
     name = models.CharField(_("Name"), max_length=128)
146
-    code = models.SlugField(_("Code"), max_length=128, help_text=_("""This is used within
147
-        forms to identify this source type"""))
168
+    code = models.SlugField(_("Code"), max_length=128,
169
+       help_text=_("This is used within forms to identify this source type"))
148 170
 
149 171
     class Meta:
150 172
         verbose_name = _("Source Type")
@@ -160,14 +182,16 @@ class SourceType(models.Model):
160 182
 
161 183
 
162 184
 class Bankcard(models.Model):
163
-    user = models.ForeignKey('auth.User', related_name='bankcards', verbose_name=_("User"))
185
+    user = models.ForeignKey('auth.User', related_name='bankcards',
186
+                             verbose_name=_("User"))
164 187
     card_type = models.CharField(_("Card Type"), max_length=128)
165 188
     name = models.CharField(_("Name"), max_length=255)
166 189
     number = models.CharField(_("Number"), max_length=32)
167 190
     expiry_date = models.DateField(_("Expiry Date"))
168 191
 
169 192
     # For payment partners who are storing the full card details for us
170
-    partner_reference = models.CharField(_("Partner Reference"), max_length=255, null=True, blank=True)
193
+    partner_reference = models.CharField(
194
+        _("Partner Reference"), max_length=255, null=True, blank=True)
171 195
 
172 196
     class Meta:
173 197
         verbose_name = _("Bankcard")

+ 4
- 3
oscar/apps/promotions/models.py Просмотреть файл

@@ -37,6 +37,7 @@ class LinkedPromotion(models.Model):
37 37
     def record_click(self):
38 38
         self.clicks += 1
39 39
         self.save()
40
+    record_click.alters_data = True
40 41
 
41 42
 
42 43
 class PagePromotion(LinkedPromotion):
@@ -156,9 +157,9 @@ class RawHTML(AbstractPromotion):
156 157
 
157 158
 class Image(AbstractPromotion):
158 159
     """
159
-    An image promotion is simply a named image which has an optional 
160
+    An image promotion is simply a named image which has an optional
160 161
     link to another part of the site (or another site).
161
-    
162
+
162 163
     This can be used to model both banners and pods.
163 164
     """
164 165
     _type = 'Image'
@@ -179,7 +180,7 @@ class Image(AbstractPromotion):
179 180
 class MultiImage(AbstractPromotion):
180 181
     """
181 182
     A multi-image promotion is simply a collection of image promotions
182
-    that are rendered in a specific way.  This models things like 
183
+    that are rendered in a specific way.  This models things like
183 184
     rotating banners.
184 185
     """
185 186
     _type = 'Multi-image'

+ 42
- 32
oscar/apps/shipping/models.py Просмотреть файл

@@ -13,7 +13,8 @@ class ShippingMethod(models.Model):
13 13
     description = models.TextField(_("Description"), blank=True)
14 14
 
15 15
     # We allow shipping methods to be linked to a specific set of countries
16
-    countries = models.ManyToManyField('address.Country', null=True, blank=True, verbose_name=_("Countries"))
16
+    countries = models.ManyToManyField('address.Country', null=True,
17
+                                       blank=True, verbose_name=_("Countries"))
17 18
 
18 19
     _basket = None
19 20
 
@@ -22,7 +23,6 @@ class ShippingMethod(models.Model):
22 23
         verbose_name = _("Shipping Method")
23 24
         verbose_name_plural = _("Shipping Methods")
24 25
 
25
-
26 26
     def save(self, *args, **kwargs):
27 27
         if not self.code:
28 28
             self.code = slugify(self.name)
@@ -30,7 +30,7 @@ class ShippingMethod(models.Model):
30 30
 
31 31
     def __unicode__(self):
32 32
         return self.name
33
-    
33
+
34 34
     def set_basket(self, basket):
35 35
         self._basket = basket
36 36
 
@@ -38,21 +38,27 @@ class ShippingMethod(models.Model):
38 38
 class OrderAndItemCharges(ShippingMethod):
39 39
     """
40 40
     Standard shipping method
41
-    
42
-    This method has two components: 
41
+
42
+    This method has two components:
43 43
     * a charge per order
44 44
     * a charge per item
45
-    
46
-    Many sites use shipping logic which fits into this system.  However, for more
47
-    complex shipping logic, a custom shipping method object will need to be provided
48
-    that subclasses ShippingMethod.
45
+
46
+    Many sites use shipping logic which fits into this system.  However, for
47
+    more complex shipping logic, a custom shipping method object will need to
48
+    be provided that subclasses ShippingMethod.
49 49
     """
50
-    price_per_order = models.DecimalField(_("Price per order"), decimal_places=2, max_digits=12, default=D('0.00'))
51
-    price_per_item = models.DecimalField(_("Price per item"), decimal_places=2, max_digits=12, default=D('0.00'))
52
-    
50
+    price_per_order = models.DecimalField(
51
+        _("Price per order"), decimal_places=2, max_digits=12,
52
+        default=D('0.00'))
53
+    price_per_item = models.DecimalField(
54
+        _("Price per item"), decimal_places=2, max_digits=12,
55
+        default=D('0.00'))
56
+
53 57
     # If basket value is above this threshold, then shipping is free
54
-    free_shipping_threshold = models.DecimalField(_("Free Shipping"), decimal_places=2, max_digits=12, blank=True, null=True)
55
-    
58
+    free_shipping_threshold = models.DecimalField(
59
+        _("Free Shipping"), decimal_places=2, max_digits=12, blank=True,
60
+        null=True)
61
+
56 62
     _basket = None
57 63
 
58 64
     class Meta:
@@ -61,7 +67,7 @@ class OrderAndItemCharges(ShippingMethod):
61 67
 
62 68
     def set_basket(self, basket):
63 69
         self._basket = basket
64
-    
70
+
65 71
     def basket_charge_incl_tax(self):
66 72
         """
67 73
         Return basket total including tax
@@ -69,38 +75,42 @@ class OrderAndItemCharges(ShippingMethod):
69 75
         if self.free_shipping_threshold != None and \
70 76
                 self._basket.total_incl_tax >= self.free_shipping_threshold:
71 77
             return D('0.00')
72
-        
78
+
73 79
         charge = self.price_per_order
74 80
         for line in self._basket.lines.all():
75 81
             charge += line.quantity * self.price_per_item
76 82
         return charge
77
-    
83
+
78 84
     def basket_charge_excl_tax(self):
79 85
         """
80
-        Return basket total excluding tax.  
81
-        
86
+        Return basket total excluding tax.
87
+
82 88
         Default implementation assumes shipping is tax free.
83 89
         """
84 90
         return self.basket_charge_incl_tax()
85 91
 
86 92
 
87 93
 class WeightBased(ShippingMethod):
88
-    upper_charge = models.DecimalField(_("Upper Charge"), decimal_places=2, max_digits=12, null=True,
89
-                                      help_text=_("""This is the charge when the
90
-                                       weight of the basket is greater than all
91
-                                      the weight bands"""))
94
+    upper_charge = models.DecimalField(
95
+        _("Upper Charge"), decimal_places=2, max_digits=12, null=True,
96
+        help_text=_("This is the charge when the weight of the basket "
97
+                    "is greater than all the weight bands"""))
92 98
 
93 99
     weight_attribute = 'weight'
94
-    default_weight = models.DecimalField(_("Default Weight"), decimal_places=2, max_digits=12, default=D('0.00'),
95
-                        help_text=_("""Default product weight in Kg when no
96
-                                        weight attribute is defined"""))
100
+    default_weight = models.DecimalField(
101
+        _("Default Weight"), decimal_places=2, max_digits=12,
102
+        default=D('0.00'),
103
+        help_text=_("Default product weight in Kg when no weight attribute "
104
+                    "is defined"))
97 105
 
98 106
     class Meta:
99 107
         verbose_name = _("Weight-based Shipping Method")
100 108
         verbose_name_plural = _("Weight-based Shipping Methods")
101 109
 
102 110
     def basket_charge_incl_tax(self):
103
-        weight = Scales(attribute_code=self.weight_attribute, default_weight=self.default_weight).weigh_basket(self._basket)
111
+        weight = Scales(attribute_code=self.weight_attribute,
112
+                        default_weight=self.default_weight).weigh_basket(
113
+                            self._basket)
104 114
         band = self.get_band_for_weight(weight)
105 115
         if not band:
106 116
             if self.bands.all().count() > 0 and self.upper_charge:
@@ -108,10 +118,10 @@ class WeightBased(ShippingMethod):
108 118
             else:
109 119
                 return D('0.00')
110 120
         return band.charge
111
-    
121
+
112 122
     def basket_charge_excl_tax(self):
113 123
         return self.basket_charge_incl_tax()
114
-        
124
+
115 125
     def get_band_for_weight(self, weight):
116 126
         """
117 127
         Return the weight band for a given weight
@@ -133,7 +143,7 @@ class WeightBand(models.Model):
133 143
                                                 limit will be determine by the
134 144
                                                 other weight bands"""))
135 145
     charge = models.DecimalField(_("Charge"), decimal_places=2, max_digits=12)
136
-    
146
+
137 147
     @property
138 148
     def weight_from(self):
139 149
         lower_bands = self.method.bands.filter(
@@ -141,11 +151,11 @@ class WeightBand(models.Model):
141 151
         if not lower_bands:
142 152
             return D('0.00')
143 153
         return lower_bands[0].upper_limit
144
-    
154
+
145 155
     @property
146 156
     def weight_to(self):
147 157
         return self.upper_limit
148
-    
158
+
149 159
     class Meta:
150 160
         ordering = ['upper_limit']
151 161
         verbose_name = _("Weight Band")

+ 2
- 0
oscar/apps/voucher/abstract_models.py Просмотреть файл

@@ -112,6 +112,7 @@ class AbstractVoucher(models.Model):
112 112
             self.applications.create(voucher=self, order=order)
113 113
         self.num_orders += 1
114 114
         self.save()
115
+    record_usage.alters_data = True
115 116
 
116 117
     def record_discount(self, discount):
117 118
         """
@@ -119,6 +120,7 @@ class AbstractVoucher(models.Model):
119 120
         """
120 121
         self.total_discount += discount
121 122
         self.save()
123
+    record_discount.alters_data = True
122 124
 
123 125
     @property
124 126
     def benefit(self):

Загрузка…
Отмена
Сохранить