Исправлена ошибка списания товара при завершении заказа
Проблема: При переводе заказа в статус 'completed' возникала ошибка "Не удалось создать Sale для заказа", т.к. резервы этого же заказа блокировали списание товара. Причина: write_off_by_fifo() считал все резервы со статусом 'reserved' как занятые, включая резервы текущего заказа, которые ещё не были переведены в 'converted_to_sale'. Решение: - Добавлен параметр exclude_order в write_off_by_fifo() для исключения резервов конкретного заказа из расчёта занятого товара - SaleProcessor.create_sale() теперь передаёт order в write_off_by_fifo() - Добавлены транзакции в views для атомарности операций с заказами: при ошибке в сигналах статус заказа откатывается вместе со всеми связанными изменениями 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -70,7 +70,7 @@ class StockBatchManager:
|
||||
return batch
|
||||
|
||||
@staticmethod
|
||||
def write_off_by_fifo(product, warehouse, quantity_to_write_off):
|
||||
def write_off_by_fifo(product, warehouse, quantity_to_write_off, exclude_order=None):
|
||||
"""
|
||||
Списать товар по FIFO (старые партии первыми).
|
||||
ВАЖНО: Учитывает зарезервированное количество товара.
|
||||
@@ -80,6 +80,9 @@ class StockBatchManager:
|
||||
product: объект Product
|
||||
warehouse: объект Warehouse
|
||||
quantity_to_write_off: Decimal - сколько списать
|
||||
exclude_order: (опционально) объект Order - исключить резервы этого заказа из расчёта.
|
||||
Используется при переводе заказа в 'completed', когда резервы
|
||||
заказа ещё не переведены в 'converted_to_sale'.
|
||||
|
||||
Returns:
|
||||
list: [(batch, qty_written), ...] - какие партии и сколько списано
|
||||
@@ -93,11 +96,16 @@ class StockBatchManager:
|
||||
allocations = []
|
||||
|
||||
# Получаем общее количество зарезервированного товара (все резервы со статусом 'reserved')
|
||||
total_reserved = Reservation.objects.filter(
|
||||
# Исключаем резервы заказа, для которого делается списание (если передан)
|
||||
reservation_filter = Reservation.objects.filter(
|
||||
product=product,
|
||||
warehouse=warehouse,
|
||||
status='reserved'
|
||||
).aggregate(total=Sum('quantity'))['total'] or Decimal('0')
|
||||
)
|
||||
if exclude_order:
|
||||
reservation_filter = reservation_filter.exclude(order_item__order=exclude_order)
|
||||
|
||||
total_reserved = reservation_filter.aggregate(total=Sum('quantity'))['total'] or Decimal('0')
|
||||
|
||||
# Получаем партии по FIFO
|
||||
batches = StockBatchManager.get_batches_for_fifo(product, warehouse)
|
||||
|
||||
Reference in New Issue
Block a user