浏览代码

Merge pull request #3922 from viggo-devries/consume_atomic_state

Atomically consume allocations and stock
master
Joey 3 年前
父节点
当前提交
ce125497f0
没有帐户链接到提交者的电子邮件
共有 1 个文件被更改,包括 63 次插入28 次删除
  1. 63
    28
      src/oscar/apps/partner/abstract_models.py

+ 63
- 28
src/oscar/apps/partner/abstract_models.py 查看文件

1
 from django.db import models, router
1
 from django.db import models, router
2
-from django.db.models import F, Value, signals
3
-from django.db.models.functions import Coalesce
2
+from django.db.models import F, signals
3
+from django.db.models.functions import Coalesce, Least
4
 from django.utils.functional import cached_property
4
 from django.utils.functional import cached_property
5
 from django.utils.timezone import now
5
 from django.utils.timezone import now
6
 from django.utils.translation import gettext_lazy as _
6
 from django.utils.translation import gettext_lazy as _
185
         # Doesn't make sense to allocate if stock tracking is off.
185
         # Doesn't make sense to allocate if stock tracking is off.
186
         if not self.can_track_allocations:
186
         if not self.can_track_allocations:
187
             return
187
             return
188
+
188
         # Send the pre-save signal
189
         # Send the pre-save signal
189
-        signals.pre_save.send(
190
-            sender=self.__class__,
191
-            instance=self,
192
-            created=False,
193
-            raw=False,
194
-            using=router.db_for_write(self.__class__, instance=self))
190
+        self.pre_save_signal()
195
 
191
 
196
         # Atomic update
192
         # Atomic update
197
-        (self.__class__.objects
198
-            .filter(pk=self.pk)
199
-            .update(num_allocated=(
200
-                Coalesce(F('num_allocated'), Value(0)) + quantity)))
193
+        (
194
+            self.__class__.objects.filter(pk=self.pk).update(
195
+                num_allocated=(Coalesce(F("num_allocated"), 0) + quantity)
196
+            )
197
+        )
201
 
198
 
202
         # Make sure the current object is up-to-date
199
         # Make sure the current object is up-to-date
203
-        if self.num_allocated is None:
204
-            self.num_allocated = 0
205
-        self.num_allocated += quantity
200
+        self.refresh_from_db(fields=["num_allocated"])
206
 
201
 
207
         # Send the post-save signal
202
         # Send the post-save signal
208
-        signals.post_save.send(
209
-            sender=self.__class__,
210
-            instance=self,
211
-            created=False,
212
-            raw=False,
213
-            using=router.db_for_write(self.__class__, instance=self))
203
+        self.post_save_signal()
214
 
204
 
215
     allocate.alters_data = True
205
     allocate.alters_data = True
216
 
206
 
232
         if not self.is_allocation_consumption_possible(quantity):
222
         if not self.is_allocation_consumption_possible(quantity):
233
             raise InvalidStockAdjustment(
223
             raise InvalidStockAdjustment(
234
                 _('Invalid stock consumption request'))
224
                 _('Invalid stock consumption request'))
235
-        self.num_allocated -= quantity
236
-        self.num_in_stock -= quantity
237
-        self.save()
225
+
226
+        # send the pre save signal
227
+        self.pre_save_signal()
228
+
229
+        # Atomically consume allocations and stock
230
+        (
231
+            self.__class__.objects.filter(pk=self.pk).update(
232
+                num_allocated=(Coalesce(F("num_allocated"), 0) - quantity),
233
+                num_in_stock=(Coalesce(F("num_in_stock"), 0) - quantity),
234
+            )
235
+        )
236
+
237
+        # Make sure current object is up-to-date
238
+        self.refresh_from_db(fields=["num_allocated", "num_in_stock"])
239
+
240
+        # Send the post-save signal
241
+        self.post_save_signal()
242
+
238
     consume_allocation.alters_data = True
243
     consume_allocation.alters_data = True
239
 
244
 
240
     def cancel_allocation(self, quantity):
245
     def cancel_allocation(self, quantity):
241
         if not self.can_track_allocations:
246
         if not self.can_track_allocations:
242
             return
247
             return
243
-        # We ignore requests that request a cancellation of more than the
244
-        # amount already allocated.
245
-        self.num_allocated -= min(self.num_allocated, quantity)
246
-        self.save()
248
+
249
+        # send the pre save signal
250
+        self.pre_save_signal()
251
+
252
+        # Atomically consume allocations
253
+        (
254
+            self.__class__.objects.filter(pk=self.pk).update(
255
+                num_allocated=Coalesce(F("num_allocated"), 0)
256
+                - Least(Coalesce(F("num_allocated"), 0), quantity),
257
+            )
258
+        )
259
+
260
+        # Make sure current object is up-to-date
261
+        self.refresh_from_db(fields=["num_allocated"])
262
+
263
+        # Send the post-save signal
264
+        self.post_save_signal()
265
+
247
     cancel_allocation.alters_data = True
266
     cancel_allocation.alters_data = True
248
 
267
 
268
+    def pre_save_signal(self):
269
+        signals.pre_save.send(
270
+            sender=self.__class__,
271
+            instance=self,
272
+            created=False,
273
+            raw=False,
274
+            using=router.db_for_write(self.__class__, instance=self))
275
+
276
+    def post_save_signal(self):
277
+        signals.post_save.send(
278
+            sender=self.__class__,
279
+            instance=self,
280
+            created=False,
281
+            raw=False,
282
+            using=router.db_for_write(self.__class__, instance=self))
283
+
249
     @property
284
     @property
250
     def is_below_threshold(self):
285
     def is_below_threshold(self):
251
         if self.low_stock_threshold is None:
286
         if self.low_stock_threshold is None:

正在加载...
取消
保存