fix(orders): исправить удаление позиций заказа в формсете

- Исправлена логика удаления inline-форм для позиций заказа
- Добавлена обработка удаления сохранённых и новых форм
- Добавлено поле id и DELETE в OrderItemForm для корректной работы формсета
- Добавлена проверка на null для created_by на странице отладки
- Расширены права доступа к отладочной странице: теперь доступна owner и manager
- Добавлено логирование для отладки процесса обновления заказа
This commit is contained in:
2026-01-18 17:16:34 +03:00
parent ab1e8ebd18
commit 0d882781da
6 changed files with 150 additions and 25 deletions

View File

@@ -323,6 +323,30 @@ def order_update(request, order_number):
form = OrderForm(request.POST, instance=order)
formset = OrderItemFormSet(request.POST, instance=order)
# Логирование для отладки удаления позиций заказа
print("\n=== DEBUG ORDER UPDATE ===")
print(f"POST data keys: {list(request.POST.keys())}")
print(f"items-TOTAL_FORMS: {request.POST.get('items-TOTAL_FORMS')}")
print(f"items-INITIAL_FORMS: {request.POST.get('items-INITIAL_FORMS')}")
# Проверяем, какие формы были отмечены для удаления
total_forms = int(request.POST.get('items-TOTAL_FORMS', 0))
for i in range(total_forms):
delete_field = request.POST.get(f'items-{i}-DELETE')
has_id = bool(request.POST.get(f'items-{i}-id'))
print(f"Form {i}: DELETE={delete_field}, has_id={has_id}")
print("=========================\n")
print(f"Form is valid: {form.is_valid()}")
print(f"Formset is valid: {formset.is_valid()}")
if not form.is_valid():
print(f"Form errors: {form.errors}")
if not formset.is_valid():
print(f"Formset errors: {formset.errors}")
for i, form_err in enumerate(formset.errors):
if form_err:
print(f"Form {i} errors: {form_err}")
if form.is_valid() and formset.is_valid():
try:
with transaction.atomic():
@@ -340,11 +364,28 @@ def order_update(request, order_number):
order.modified_by = request.user
order.save()
print(f"Before formset.save(): Order has {order.items.count()} items")
# Логирование форм, отмеченных для удаления
print("Forms in formset:")
for i, form in enumerate(formset):
if hasattr(form, 'cleaned_data') and form.cleaned_data:
delete_flag = form.cleaned_data.get('DELETE', False)
form_id = form.cleaned_data.get('id')
print(f" Form {i}: id={form_id}, DELETE={delete_flag}, has_changed={form.has_changed()}")
print(f" Full cleaned_data: {form.cleaned_data}")
if delete_flag:
print(f" -> This form should be deleted")
else:
print(f" Form {i}: No cleaned_data or empty")
formset.save()
print(f"After formset.save(): Order has {order.items.count()} items")
print(f"Forms marked for deletion: {[form for form in formset if form.cleaned_data.get('DELETE')] if formset.can_delete else 'N/A'}")
# Проверяем, является ли заказ черновиком
is_draft = order.status and order.status.code == 'draft'
# Получаем данные из формы (уже провалидированы)
delivery_type = form.cleaned_data.get('delivery_type')
delivery_date = form.cleaned_data.get('delivery_date')
@@ -352,7 +393,10 @@ def order_update(request, order_number):
time_to = form.cleaned_data.get('time_to')
delivery_cost = form.cleaned_data.get('delivery_cost', Decimal('0'))
pickup_warehouse = form.cleaned_data.get('pickup_warehouse')
print(f"[DEBUG] Delivery data - type: {delivery_type}, date: {delivery_date}, time_from: {time_from}, time_to: {time_to}")
print(f"[DEBUG] Is draft: {is_draft}, address: {form.cleaned_data.get('address_street')}")
# Обрабатываем адрес для курьерской доставки (даже для черновиков, если указан)
address = None
if delivery_type == Delivery.DELIVERY_TYPE_COURIER:
@@ -360,13 +404,13 @@ def order_update(request, order_number):
address = AddressService.process_address_from_form(order, form.cleaned_data)
if address and not address.pk:
address.save()
# Создаем или обновляем Delivery
# Для черновиков создаем Delivery без обязательных проверок, чтобы сохранить адрес
if is_draft:
# Для черновиков создаем Delivery, если есть хотя бы адрес или данные доставки
if address or delivery_type or pickup_warehouse or delivery_date:
Delivery.objects.update_or_create(
delivery_obj, created = Delivery.objects.update_or_create(
order=order,
defaults={
'delivery_type': delivery_type or Delivery.DELIVERY_TYPE_COURIER,
@@ -378,6 +422,7 @@ def order_update(request, order_number):
'cost': delivery_cost if delivery_cost else Decimal('0')
}
)
print(f"[DEBUG] Created/Updated Delivery for draft: {delivery_obj.delivery_date}, created: {created}")
elif hasattr(order, 'delivery'):
# Если заказ стал черновиком и нет данных доставки, удаляем Delivery
order.delivery.delete()
@@ -385,7 +430,7 @@ def order_update(request, order_number):
# Для не-черновиков проверяем обязательные поля
if not delivery_type or not delivery_date:
raise ValidationError('Необходимо указать способ доставки и дату доставки')
if delivery_type == Delivery.DELIVERY_TYPE_COURIER:
# Для курьерской доставки нужен адрес
if not address:
@@ -394,7 +439,7 @@ def order_update(request, order_number):
# Для самовывоза нужен склад
if not pickup_warehouse:
raise ValidationError('Для самовывоза необходимо выбрать склад')
# Создаем или обновляем Delivery
delivery, created = Delivery.objects.update_or_create(
order=order,
@@ -408,6 +453,7 @@ def order_update(request, order_number):
'cost': delivery_cost if delivery_cost else Decimal('0')
}
)
print(f"[DEBUG] Created/Updated Delivery for non-draft: {delivery.delivery_date}, created: {created}")
# Пересчитываем итоговую стоимость
order.calculate_total()