This commit is contained in:
2025-11-04 11:00:05 +03:00
parent 706ee5d8e8
commit b24d5bcdee
13 changed files with 1383 additions and 72 deletions

View File

@@ -244,3 +244,66 @@ class StockBatchManager:
batch.is_active = False
batch.save(update_fields=['is_active'])
@staticmethod
@transaction.atomic
def transfer_product_by_fifo(product, from_warehouse, to_warehouse, quantity):
"""
Переместить товар с одного склада на другой по FIFO логике.
Старые партии перемещаются первыми.
Args:
product: объект Product
from_warehouse: объект Warehouse (источник)
to_warehouse: объект Warehouse (назначение)
quantity: Decimal - количество товара для перемещения
Returns:
list: [(source_batch, qty_transferred, new_batch), ...]
список кортежей с исходной партией, количеством и созданной партией
Raises:
ValueError: если недостаточно товара на складе-источнике
"""
# Получаем партии по FIFO (старые первыми)
allocations = StockBatchManager.get_batches_for_fifo(product, from_warehouse)
result = []
remaining = quantity
for batch in allocations:
if remaining <= 0:
break
# Определяем сколько перемещаем из этой партии
qty_to_transfer = min(batch.quantity, remaining)
# Уменьшаем исходную партию
batch.quantity -= qty_to_transfer
if batch.quantity <= 0:
batch.is_active = False
batch.save(update_fields=['quantity', 'is_active', 'updated_at'])
# Создаем новую партию на целевом складе с СОХРАНЕНИЕМ cost_price
new_batch = StockBatch.objects.create(
product=product,
warehouse=to_warehouse,
quantity=qty_to_transfer,
cost_price=batch.cost_price # ВАЖНО: сохраняем цену!
)
result.append((batch, qty_to_transfer, new_batch))
remaining -= qty_to_transfer
# Проверяем что было достаточно товара
if remaining > 0:
raise ValueError(
f"Недостаточно товара '{product.name}' на складе '{from_warehouse.name}'. "
f"Не хватает {remaining} шт из запрашиваемых {quantity} шт"
)
# Обновляем кеш остатков на обоих складах
StockBatchManager.refresh_stock_cache(product, from_warehouse)
StockBatchManager.refresh_stock_cache(product, to_warehouse)
return result