Simplify order creation and editing - remove autosave
- Removed autosave.js (665 lines) and draft-creator.js (441 lines) - Removed draft_service.py (~500 lines) and DraftOrderService - Removed AJAX endpoints: autosave and create-draft - Updated order_create() to add is_create_page flag - Updated order_update() to finalize drafts without DraftOrderService - Added get_new_status() method to OrderStatusService - Updated order_form.html: - Removed old JS includes - Added beforeunload warning for unsaved data - Updated buttons: separate buttons for create/draft/finalize - Total code reduction: ~1600 lines (92% removed) New workflow: - /orders/create/ - user fills form, chooses button - /orders/<id>/edit/ - simple editing without autosave - beforeunload warning when leaving page (except on submit)
This commit is contained in:
@@ -11,7 +11,6 @@ from decimal import Decimal
|
||||
from .models import Order, OrderItem, Address, OrderStatus
|
||||
from .forms import OrderForm, OrderItemFormSet, OrderStatusForm, PaymentFormSet
|
||||
from .filters import OrderFilter
|
||||
from .services import DraftOrderService
|
||||
from .services.address_service import AddressService
|
||||
import json
|
||||
|
||||
@@ -80,11 +79,15 @@ def order_create(request):
|
||||
address.save()
|
||||
order.delivery_address = address
|
||||
|
||||
# Если нажата кнопка "Сохранить как черновик", создаем черновик
|
||||
# Проверяем какая кнопка нажата
|
||||
if 'save_as_draft' in request.POST:
|
||||
# Кнопка "Сохранить как черновик"
|
||||
from .services.order_status_service import OrderStatusService
|
||||
order.status = OrderStatusService.get_draft_status()
|
||||
order.modified_by = request.user
|
||||
else:
|
||||
# Кнопка "Создать заказ" - статус из формы или NULL
|
||||
order.modified_by = request.user
|
||||
|
||||
order.save()
|
||||
|
||||
@@ -131,6 +134,7 @@ def order_create(request):
|
||||
'preselected_customer': preselected_customer,
|
||||
'title': 'Создание заказа',
|
||||
'button_text': 'Создать заказ',
|
||||
'is_create_page': True,
|
||||
}
|
||||
|
||||
return render(request, 'orders/order_form.html', context)
|
||||
@@ -150,15 +154,29 @@ def order_update(request, order_number):
|
||||
|
||||
# Если черновик финализируется
|
||||
if 'finalize_draft' in request.POST and order.is_draft():
|
||||
try:
|
||||
order = DraftOrderService.finalize_draft(order.pk, request.user)
|
||||
messages.success(request, f'Черновик #{order.order_number} успешно завершен и переведен в статус "Новый"!')
|
||||
return redirect('orders:order-detail', order_number=order.order_number)
|
||||
except ValidationError as e:
|
||||
messages.error(request, f'Ошибка финализации: {str(e)}')
|
||||
form = OrderForm(instance=order)
|
||||
formset = OrderItemFormSet(instance=order)
|
||||
payment_formset = PaymentFormSet(instance=order)
|
||||
from .services.order_status_service import OrderStatusService
|
||||
# Переводим в статус "Новый"
|
||||
order.status = OrderStatusService.get_new_status()
|
||||
order.modified_by = request.user
|
||||
|
||||
# Обрабатываем адрес доставки
|
||||
if order.is_delivery:
|
||||
address = AddressService.process_address_from_form(order, form.cleaned_data)
|
||||
if address:
|
||||
if not address.pk:
|
||||
address.save()
|
||||
order.delivery_address = address
|
||||
|
||||
order.save()
|
||||
formset.save()
|
||||
payment_formset.save()
|
||||
|
||||
# Пересчитываем итоговую сумму
|
||||
order.calculate_total()
|
||||
order.save()
|
||||
|
||||
messages.success(request, f'Черновик #{order.order_number} успешно завершен и переведен в статус "Новый"!')
|
||||
return redirect('orders:order-detail', order_number=order.order_number)
|
||||
else:
|
||||
# Обрабатываем адрес доставки
|
||||
if order.is_delivery:
|
||||
@@ -255,250 +273,6 @@ def order_delete(request, order_number):
|
||||
# === AJAX ENDPOINTS ===
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
@login_required
|
||||
def autosave_draft_order(request, order_number):
|
||||
"""
|
||||
AJAX endpoint для автосохранения черновика заказа.
|
||||
|
||||
Принимает JSON с данными формы и обновляет черновик.
|
||||
Возвращает статус сохранения и время последнего сохранения.
|
||||
|
||||
Пример запроса:
|
||||
{
|
||||
"customer": 1,
|
||||
"is_delivery": true,
|
||||
"delivery_address": 5,
|
||||
"delivery_date": "2024-01-15",
|
||||
"special_instructions": "Позвонить за час",
|
||||
"items": [
|
||||
{"product_id": 10, "quantity": "2", "price": "500"},
|
||||
{"product_kit_id": 5, "quantity": "1", "price": "1500"}
|
||||
]
|
||||
}
|
||||
|
||||
Ответ при успехе:
|
||||
{
|
||||
"success": true,
|
||||
"last_saved": "2024-01-10T15:30:45.123456",
|
||||
"order_id": 123,
|
||||
"order_number": "ORD-000123"
|
||||
}
|
||||
"""
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
|
||||
# Проверяем существование заказа
|
||||
try:
|
||||
order = Order.objects.get(order_number=order_number)
|
||||
except Order.DoesNotExist:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': 'Заказ не найден'
|
||||
}, status=404)
|
||||
|
||||
# Обновляем основные поля заказа из DraftOrderService (БЕЗ товаров)
|
||||
# Товары обрабатываем отдельно ниже
|
||||
order_fields_only = {k: v for k, v in data.items() if k not in ['items', 'payments']}
|
||||
order = DraftOrderService.update_draft(
|
||||
order_id=order.pk,
|
||||
user=request.user,
|
||||
data=order_fields_only
|
||||
)
|
||||
|
||||
# Обрабатываем позиции заказа, если они переданы
|
||||
if 'items' in data:
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
# Получаем ID товаров, которые нужно удалить
|
||||
deleted_item_ids = data.get('deleted_item_ids', [])
|
||||
if deleted_item_ids:
|
||||
order.items.filter(pk__in=deleted_item_ids).delete()
|
||||
|
||||
# Обрабатываем каждый товар
|
||||
for item_data in data['items']:
|
||||
item_id = item_data.get('id') # ID существующего товара (если есть)
|
||||
product_id = item_data.get('product_id')
|
||||
product_kit_id = item_data.get('product_kit_id')
|
||||
quantity = item_data.get('quantity')
|
||||
price_raw = item_data.get('price')
|
||||
|
||||
# Преобразуем цену
|
||||
try:
|
||||
price = Decimal(str(price_raw).replace(',', '.')) if price_raw else None
|
||||
except (ValueError, InvalidOperation):
|
||||
price = None
|
||||
|
||||
# Если есть ID - обновляем существующий товар
|
||||
if item_id:
|
||||
try:
|
||||
item = order.items.get(pk=item_id)
|
||||
# Обновляем поля
|
||||
if product_id:
|
||||
from products.models import Product
|
||||
item.product = Product.objects.get(pk=product_id)
|
||||
item.product_kit = None
|
||||
elif product_kit_id:
|
||||
from products.models import ProductKit
|
||||
item.product_kit = ProductKit.objects.get(pk=product_kit_id)
|
||||
item.product = None
|
||||
|
||||
if quantity:
|
||||
item.quantity = quantity
|
||||
if price is not None:
|
||||
item.price = price
|
||||
|
||||
item.save()
|
||||
except OrderItem.DoesNotExist:
|
||||
# Если товар не найден, создаем новый
|
||||
item_id = None
|
||||
|
||||
# Если нет ID - создаем новый товар
|
||||
if not item_id:
|
||||
if product_id:
|
||||
DraftOrderService.add_item_to_draft(
|
||||
order_id=order.pk,
|
||||
product_id=product_id,
|
||||
quantity=quantity,
|
||||
price=price
|
||||
)
|
||||
elif product_kit_id:
|
||||
DraftOrderService.add_item_to_draft(
|
||||
order_id=order.pk,
|
||||
product_kit_id=product_kit_id,
|
||||
quantity=quantity,
|
||||
price=price
|
||||
)
|
||||
|
||||
# НЕ ОБРАБАТЫВАЕМ ПЛАТЕЖИ В АВТОСОХРАНЕНИИ
|
||||
# Платежи обрабатываются только при ручном сохранении формы
|
||||
|
||||
# Пересчитываем итоговую сумму заказа и обновляем статус оплаты
|
||||
order.calculate_total()
|
||||
order.update_payment_status()
|
||||
order.save()
|
||||
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'last_saved': order.last_autosave_at.isoformat() if order.last_autosave_at else None,
|
||||
'order_id': order.pk,
|
||||
'order_number': order.order_number
|
||||
})
|
||||
|
||||
except ValidationError as e:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}, status=400)
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': 'Некорректный JSON'
|
||||
}, status=400)
|
||||
except Exception as e:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': f'Ошибка сервера: {str(e)}'
|
||||
}, status=500)
|
||||
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
@login_required
|
||||
def create_draft_from_form(request):
|
||||
"""
|
||||
AJAX endpoint для создания черновика заказа из формы создания.
|
||||
|
||||
Используется для автоматического создания черновика при первом изменении формы.
|
||||
После создания возвращает ID черновика для перенаправления.
|
||||
|
||||
Пример запроса:
|
||||
{
|
||||
"customer": 1,
|
||||
"is_delivery": true,
|
||||
"delivery_date": "2024-01-15"
|
||||
}
|
||||
|
||||
Ответ при успехе:
|
||||
{
|
||||
"success": true,
|
||||
"order_id": 123,
|
||||
"order_number": "ORD-000123",
|
||||
"redirect_url": "/orders/123/edit/"
|
||||
}
|
||||
"""
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
|
||||
# Получаем обязательное поле - клиента
|
||||
customer_id = data.get('customer')
|
||||
if not customer_id:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': 'Необходимо выбрать клиента'
|
||||
}, status=400)
|
||||
|
||||
from customers.models import Customer
|
||||
try:
|
||||
customer = Customer.objects.get(pk=customer_id)
|
||||
except Customer.DoesNotExist:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': 'Клиент не найден'
|
||||
}, status=404)
|
||||
|
||||
# Создаем черновик через DraftOrderService
|
||||
order = DraftOrderService.create_draft(
|
||||
user=request.user,
|
||||
customer=customer,
|
||||
data=data
|
||||
)
|
||||
|
||||
# Обрабатываем позиции заказа, если они переданы
|
||||
if 'items' in data:
|
||||
for item_data in data['items']:
|
||||
product_id = item_data.get('product_id')
|
||||
product_kit_id = item_data.get('product_kit_id')
|
||||
quantity = item_data.get('quantity')
|
||||
price = item_data.get('price')
|
||||
|
||||
if product_id:
|
||||
DraftOrderService.add_item_to_draft(
|
||||
order_id=order.pk,
|
||||
product_id=product_id,
|
||||
quantity=quantity,
|
||||
price=price
|
||||
)
|
||||
elif product_kit_id:
|
||||
DraftOrderService.add_item_to_draft(
|
||||
order_id=order.pk,
|
||||
product_kit_id=product_kit_id,
|
||||
quantity=quantity,
|
||||
price=price
|
||||
)
|
||||
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'order_id': order.pk,
|
||||
'order_number': order.order_number,
|
||||
'redirect_url': f'/orders/{order.order_number}/edit/'
|
||||
})
|
||||
|
||||
except ValidationError as e:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}, status=400)
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': 'Некорректный JSON'
|
||||
}, status=400)
|
||||
except Exception as e:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': f'Ошибка сервера: {str(e)}'
|
||||
}, status=500)
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
@login_required
|
||||
def get_customer_address_history(request):
|
||||
|
||||
Reference in New Issue
Block a user