From d3ac875a0e7e740cb3455a86b0af0952c7b9eb58 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Fri, 14 Nov 2025 23:00:24 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=20=D1=87=D0=B5=D1=80=D0=BD=D0=BE=D0=B2=D0=B8=D0=BA=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=BA=D0=B0=D0=B7=D0=BE=D0=B2=20=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=B0=D0=B2?= =?UTF-8?q?=D1=82=D0=BE=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблема 1: Ошибка 500 при создании черновика заказа - Поле status в модели Order является ForeignKey на OrderStatus - В коде использовались строковые значения 'draft' и 'new' вместо объектов - Это приводило к TypeError при создании/обновлении заказов Решение: - В DraftOrderService.create_draft: добавлен get_or_create для статуса 'draft' - В DraftOrderService.finalize_draft: добавлен get_or_create для статуса 'new' - В DraftOrderService.get_user_drafts: заменен фильтр status='draft' на status__code='draft' - В DraftOrderService.delete_old_drafts: заменен фильтр status='draft' на status__code='draft' - В cleanup_draft_orders.py: исправлен фильтр в режиме dry-run Проблема 2: Отсутствие автосохранения при изменении статуса - Поле status не отслеживалось в autosave.js - При смене статуса заказ не сохранялся автоматически Решение: - Добавлено поле 'select[name="status"]' в список отслеживаемых полей - Добавлен сбор значения статуса в функции collectFormData - Добавлено 'status': 'orders.OrderStatus' в fk_fields для обработки на сервере Дополнительно: - Добавлено автосохранение полей адреса доставки (улица, дом, квартира и т.д.) - Добавлено автосохранение полей получателя (имя, телефон) - Добавлена автоматическая установка address_mode='new' при наличии адреса Файлы: - orders/services/draft_service.py - orders/management/commands/cleanup_draft_orders.py - orders/static/orders/js/autosave.js 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../commands/cleanup_draft_orders.py | 2 +- myproject/orders/services/draft_service.py | 33 +++++++-- myproject/orders/static/orders/js/autosave.js | 71 +++++++++++++++++++ 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/myproject/orders/management/commands/cleanup_draft_orders.py b/myproject/orders/management/commands/cleanup_draft_orders.py index 64be32b..dc416cc 100644 --- a/myproject/orders/management/commands/cleanup_draft_orders.py +++ b/myproject/orders/management/commands/cleanup_draft_orders.py @@ -50,7 +50,7 @@ class Command(BaseCommand): cutoff_date = timezone.now() - timedelta(days=days) old_drafts = Order.objects.filter( - status='draft', + status__code='draft', last_autosave_at__lt=cutoff_date ) count = old_drafts.count() diff --git a/myproject/orders/services/draft_service.py b/myproject/orders/services/draft_service.py index 954ad20..696b21b 100644 --- a/myproject/orders/services/draft_service.py +++ b/myproject/orders/services/draft_service.py @@ -39,9 +39,21 @@ class DraftOrderService: data = data or {} with transaction.atomic(): + # Получаем или создаем статус 'draft' + from ..models import OrderStatus + draft_status, _ = OrderStatus.objects.get_or_create( + code='draft', + defaults={ + 'name': 'Черновик', + 'label': 'Черновик', + 'is_system': True, + 'color': '#808080', + } + ) + order = Order.objects.create( customer=customer, - status='draft', + status=draft_status, modified_by=user, is_delivery=data.get('is_delivery', True), delivery_address=data.get('delivery_address'), @@ -86,6 +98,7 @@ class DraftOrderService: fk_fields = { 'customer': 'customers.Customer', 'pickup_shop': 'shops.Shop', + 'status': 'orders.OrderStatus', } simple_fields = [ @@ -308,8 +321,20 @@ class DraftOrderService: # Выполняем полную валидацию модели order.full_clean() + # Получаем или создаем статус 'new' + from ..models import OrderStatus + new_status, _ = OrderStatus.objects.get_or_create( + code='new', + defaults={ + 'name': 'Новый', + 'label': 'Новый', + 'is_system': True, + 'color': '#0d6efd', + } + ) + # Изменяем статус на 'new' - order.status = 'new' + order.status = new_status order.modified_by = user order.last_autosave_at = None # Очищаем, т.к. заказ больше не черновик order.save() @@ -335,7 +360,7 @@ class DraftOrderService: QuerySet: Черновики заказов """ drafts = Order.objects.filter( - status='draft', + status__code='draft', modified_by=user ).select_related('customer', 'delivery_address', 'pickup_shop') @@ -361,7 +386,7 @@ class DraftOrderService: # Находим старые черновики old_drafts = Order.objects.filter( - status='draft', + status__code='draft', last_autosave_at__lt=cutoff_date ) diff --git a/myproject/orders/static/orders/js/autosave.js b/myproject/orders/static/orders/js/autosave.js index dfd567b..c7066e2 100644 --- a/myproject/orders/static/orders/js/autosave.js +++ b/myproject/orders/static/orders/js/autosave.js @@ -136,6 +136,7 @@ // Слушаем изменения в основных полях заказа const fieldsToWatch = [ 'select[name="customer"]', + 'select[name="status"]', 'input[name="delivery_date"]', 'input[name="delivery_time_start"]', 'input[name="delivery_time_end"]', @@ -147,6 +148,17 @@ 'input[type="radio"]', 'select[name="delivery_address"]', 'select[name="pickup_shop"]', + // Поля адреса доставки + 'input[name="address_street"]', + 'input[name="address_building_number"]', + 'input[name="address_apartment_number"]', + 'input[name="address_entrance"]', + 'input[name="address_floor"]', + 'input[name="address_intercom_code"]', + 'textarea[name="address_delivery_instructions"]', + // Поля получателя + 'input[name="recipient_name"]', + 'input[name="recipient_phone"]', ]; fieldsToWatch.forEach(selector => { @@ -290,6 +302,11 @@ data.customer = parseInt(customerField.value); } + const statusField = form.querySelector('select[name="status"]'); + if (statusField && statusField.value) { + data.status = parseInt(statusField.value); + } + const deliveryDateField = form.querySelector('input[name="delivery_date"]'); if (deliveryDateField && deliveryDateField.value) { data.delivery_date = deliveryDateField.value; @@ -352,6 +369,60 @@ data.pickup_shop = parseInt(pickupShopField.value); } + // Поля адреса доставки (новая логика с прямым вводом) + const addressStreetField = form.querySelector('input[name="address_street"]'); + if (addressStreetField && addressStreetField.value) { + data.address_street = addressStreetField.value; + // Указываем режим "новый адрес" если есть улица + data.address_mode = 'new'; + } + + const addressBuildingField = form.querySelector('input[name="address_building_number"]'); + if (addressBuildingField && addressBuildingField.value) { + data.address_building_number = addressBuildingField.value; + } + + const addressApartmentField = form.querySelector('input[name="address_apartment_number"]'); + if (addressApartmentField && addressApartmentField.value) { + data.address_apartment_number = addressApartmentField.value; + } + + const addressEntranceField = form.querySelector('input[name="address_entrance"]'); + if (addressEntranceField && addressEntranceField.value) { + data.address_entrance = addressEntranceField.value; + } + + const addressFloorField = form.querySelector('input[name="address_floor"]'); + if (addressFloorField && addressFloorField.value) { + data.address_floor = addressFloorField.value; + } + + const addressIntercomField = form.querySelector('input[name="address_intercom_code"]'); + if (addressIntercomField && addressIntercomField.value) { + data.address_intercom_code = addressIntercomField.value; + } + + const addressInstructionsField = form.querySelector('textarea[name="address_delivery_instructions"]'); + if (addressInstructionsField && addressInstructionsField.value) { + data.address_delivery_instructions = addressInstructionsField.value; + } + + const addressConfirmField = form.querySelector('input[name="address_confirm_with_recipient"]'); + if (addressConfirmField) { + data.address_confirm_with_recipient = addressConfirmField.checked; + } + + // Поля получателя + const recipientNameField = form.querySelector('input[name="recipient_name"]'); + if (recipientNameField && recipientNameField.value) { + data.recipient_name = recipientNameField.value; + } + + const recipientPhoneField = form.querySelector('input[name="recipient_phone"]'); + if (recipientPhoneField && recipientPhoneField.value) { + data.recipient_phone = recipientPhoneField.value; + } + // Собираем позиции заказа data.items = collectOrderItems();