Fix Github issue #69
This commit is contained in:
+18
-3
@@ -23,6 +23,7 @@ from decimal import Decimal, ROUND_HALF_UP
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import stripe
|
import stripe
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
|
from django.db.models import F
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
import re
|
import re
|
||||||
import unicodedata
|
import unicodedata
|
||||||
@@ -474,10 +475,24 @@ def _get_active_reservation_ids_for_request(request: HttpRequest):
|
|||||||
|
|
||||||
|
|
||||||
def _get_available_stock_by_product(product_ids, exclude_reservation_ids=None):
|
def _get_available_stock_by_product(product_ids, exclude_reservation_ids=None):
|
||||||
|
"""Calcula stock disponible con bloqueo atómico para evitar race conditions."""
|
||||||
_release_expired_stock_reservations()
|
_release_expired_stock_reservations()
|
||||||
products = Product.objects.filter(id__in=product_ids)
|
|
||||||
|
if not product_ids:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
# Bloquear productos a nivel de fila para evitar race conditions
|
||||||
|
products = Product.objects.select_for_update().filter(id__in=product_ids)
|
||||||
stocks = {product.id: product.stock for product in products}
|
stocks = {product.id: product.stock for product in products}
|
||||||
reserved = _get_reserved_quantities_by_product(product_ids, exclude_reservation_ids=exclude_reservation_ids)
|
|
||||||
|
# Las reservas se consultan dentro de la transacción atómica
|
||||||
|
# _get_reserved_quantities_by_product hace una lectura consistente
|
||||||
|
reserved = _get_reserved_quantities_by_product(
|
||||||
|
product_ids,
|
||||||
|
exclude_reservation_ids=exclude_reservation_ids
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
product_id: max(stocks.get(product_id, 0) - reserved.get(product_id, 0), 0)
|
product_id: max(stocks.get(product_id, 0) - reserved.get(product_id, 0), 0)
|
||||||
for product_id in product_ids
|
for product_id in product_ids
|
||||||
@@ -703,7 +718,7 @@ def create_order_from_cart(request, payment_method, payment_reference="", shippi
|
|||||||
)
|
)
|
||||||
|
|
||||||
product_row = product_map.get(item.product_id)
|
product_row = product_map.get(item.product_id)
|
||||||
product_row.stock -= item.quantity
|
product_row.stock = F('stock') - item.quantity
|
||||||
product_row.save(update_fields=["stock"])
|
product_row.save(update_fields=["stock"])
|
||||||
|
|
||||||
_invalidate_product_cache(product_ids)
|
_invalidate_product_cache(product_ids)
|
||||||
|
|||||||
Reference in New Issue
Block a user