Исправлено двойное списание товаров при смене статуса заказа
Проблема: - При изменении статуса заказа на 'Выполнен' товар списывался дважды - Заказ на 10 шт создавал Sale на 10 шт, но со склада уходило 20 шт Найдено ДВЕ причины: 1. Повторное обновление резервов через .save() (inventory/signals.py) - Резервы обновлялись через res.save() каждый раз при сохранении заказа - Это вызывало сигнал update_stock_on_reservation_change - При повторном сохранении заказа происходило двойное срабатывание Решение: - Проверка дубликатов ПЕРЕД обновлением резервов - Замена .save() на .update() для массового обновления без вызова сигналов - Ручное обновление Stock после .update() 2. Двойное FIFO-списание (inventory/services/sale_processor.py) - Sale создавалась с processed=False - Сигнал process_sale_fifo срабатывал и списывал товар (1-й раз) - Затем SaleProcessor.create_sale() тоже списывал товар (2-й раз) Решение: - Sale создаётся сразу с processed=True - Сигнал не срабатывает, списание только в сервисе Дополнительно: - Ограничен выбор статусов при создании заказа только промежуточными - Статус 'Черновик' установлен по умолчанию - Убран пустой выбор '-------' из поля статуса Изменённые файлы: - myproject/orders/forms.py - настройки статусов для формы заказа - myproject/inventory/signals.py - исправление сигнала create_sale_on_order_completion - myproject/inventory/services/sale_processor.py - исправление create_sale - myproject/test_order_status_default.py - обновлён тест - DOUBLE_SALE_FIX.md - документация по исправлению
This commit is contained in:
@@ -115,6 +115,32 @@ class OrderForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Ограничиваем выбор статусов при создании заказа только промежуточными
|
||||
# (исключаем финальные положительные и отрицательные статусы)
|
||||
if not self.instance.pk:
|
||||
from .models import OrderStatus
|
||||
# Только промежуточные статусы (не финальные)
|
||||
intermediate_statuses = OrderStatus.objects.filter(
|
||||
is_positive_end=False,
|
||||
is_negative_end=False
|
||||
).order_by('order', 'name')
|
||||
self.fields['status'].queryset = intermediate_statuses
|
||||
|
||||
# Устанавливаем статус "Черновик" по умолчанию
|
||||
try:
|
||||
draft_status = OrderStatus.objects.get(code='draft', is_system=True)
|
||||
self.fields['status'].initial = draft_status.pk
|
||||
except OrderStatus.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
# При редактировании заказа доступны все статусы
|
||||
from .models import OrderStatus
|
||||
self.fields['status'].queryset = OrderStatus.objects.all().order_by('order', 'name')
|
||||
|
||||
# Делаем поле status обязательным и убираем пустой выбор "-------"
|
||||
self.fields['status'].required = True
|
||||
self.fields['status'].empty_label = None
|
||||
|
||||
# Добавляем Bootstrap классы ко всем полям
|
||||
for field_name, field in self.fields.items():
|
||||
if isinstance(field.widget, forms.CheckboxInput):
|
||||
|
||||
Reference in New Issue
Block a user