Commit Graph

290 Commits

Author SHA1 Message Date
7858c780d1 Исправлена ошибка в шаблоне tag_confirm_delete.html
Изменена переменная с 'tag' на 'object' для соответствия Django DeleteView.
Django DeleteView передаёт объект в контексте как 'object', а не как имя модели.

Исправлено:
- Заголовок страницы
- Текст подтверждения
- Ссылка на отмену (tag-detail)
- Информация о теге в карточке

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 23:29:01 +03:00
1daee88cbd Добавлено быстрое создание тегов на странице списка
API функционал:
- Создан endpoint /api/tags/create/ для AJAX создания тегов
- Валидация: пустое имя, длина, уникальность (регистронезависимо)
- Автоматическая генерация slug через модель
- Возврат JSON с данными созданного тега

UI функционал на странице списка тегов:
- Панель быстрого создания с крупным полем ввода
- Автофокус на поле при загрузке страницы
- Создание тега по нажатию Enter или клику на кнопку
- Индикатор загрузки (спиннер) во время создания
- Блокировка поля/кнопки во время запроса
- Автоматическая перезагрузка страницы после создания
- Возврат фокуса в поле при ошибке
- Красивые alert-сообщения об успехе/ошибке
- CSRF защита

Workflow: ввёл название → Enter → тег создан → фокус снова в поле → можно вводить следующий

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 23:26:40 +03:00
1a0360f8c0 Реализован полный CRUD для тегов товаров
Упрощена модель ProductTag:
- Удалены поля soft delete (is_deleted, deleted_at, deleted_by)
- Добавлено поле is_active для управления статусом
- Упрощены менеджеры и методы модели

Создан CRUD функционал:
- ProductTagForm: форма с автогенерацией slug
- Views: список, создание, просмотр, редактирование, удаление
- URL маршруты: /products/tags/*
- Шаблоны: list, form, detail, confirm_delete

Особенности:
- Поиск по названию и slug
- Фильтрация по статусу активности
- Статистика использования тегов в товарах/комплектах
- Пагинация (20 на страницу)
- Предупреждение при удалении с отображением связанных объектов
- Добавлена ссылка "Теги" в навигацию

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 23:14:01 +03:00
4a1f8266de Улучшения UX формы заказа и создания клиента
- Изменен порядок секций формы: товары перемещены выше доставки
- Добавлена защита от двойного создания клиента
- Улучшена валидация при создании клиента с детализацией ошибок
- Добавлен индикатор загрузки при сохранении клиента
- Исправлена логика обработки специальной опции создания клиента

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 21:16:48 +03:00
9394abfa3f Добавлена валидация уникальности email и phone для клиентов
Изменения:
- Добавлено ограничение unique=True для поля email в модели Customer
- Email теперь поддерживает NULL значения (несколько клиентов могут быть без email)
- Добавлены методы clean_email() и clean_phone() в CustomerForm для валидации
- Переписан API endpoint api_create_customer для использования формы вместо прямого создания
- Создано две миграции: сначала разрешение NULL, затем добавление unique constraint
- В текущей БД преобразованы пустые строки email в NULL (4 записи)

Это исправляет:
- Возможность создания дубликатов клиентов с одинаковыми email/phone
- Работает как в веб-форме, так и в модальном окне создания заказа
- Устранена уязвимость race condition через использование DB constraints

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 17:36:11 +03:00
0973121b39 Удалена устаревшая логика адресов клиентов
Исправлена ошибка AttributeError при создании нового клиента.
Адреса теперь привязаны к заказам, а не к клиентам.

- Удалено обращение к customer.addresses в customer_detail view
- Убрана секция "Адреса доставки" из шаблона customer_detail.html
- Исправлена команда create_demo_orders для работы с новой структурой

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 17:04:20 +03:00
8cc8cd1339 Исправлена персистентность типа доставки при автосохранении
Проблема: После переключения между "С доставкой" и "Самовывоз" и автосохранения, при перезагрузке страницы всегда отображался "Самовывоз", независимо от фактически сохраненного значения.

Изменения:

1. **orders/templates/orders/order_form.html**:
   - Переписана инициализация управления типом доставки
   - Код вынесен из jQuery document.ready в отдельный DOMContentLoaded обработчик
   - Разделена логика синхронизации:
     * syncDeliveryTypeFromRadio() - для обработки кликов пользователя
     * syncUIFromCheckbox() - для инициализации UI из значения чекбокса
   - Исправлен рендеринг скрытого чекбокса is_delivery с явным атрибутом checked
   - Удалена лишняя закрывающая скобка, вызывавшая JS ошибку
   - Удален дублирующийся обработчик select2:opening для выбора клиента

2. **orders/services/draft_service.py**:
   - Добавлена явная конвертация boolean полей (is_delivery, customer_is_recipient, is_anonymous)
   - Обработка различных типов данных (bool, string, None) в единый boolean
   - Добавлено логирование для отладки is_delivery (временно)

Результат: Тип доставки теперь корректно сохраняется через автосохранение и восстанавливается при перезагрузке страницы.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 16:59:24 +03:00
885ac839e2 Реализована система управления стоимостью доставки и исправлен баг выбора клиента
Изменения:

1. **Стоимость доставки (автоматическая/ручная)**:
   - Добавлено поле `is_custom_delivery_cost` в модель Order для отслеживания ручной стоимости
   - Создан сервис DeliveryCostCalculator для автоматического расчета стоимости доставки
   - Реализована логика: бесплатная доставка от 100 руб., иначе 15 руб.
   - В форме поле "Ручная стоимость доставки" - если заполнено, используется ручная стоимость, если пустое - автоматический расчет
   - Добавлены методы Order.get_delivery_cost(), set_delivery_cost(), reset_delivery_cost(), recalculate_delivery_cost()

2. **Исправление бага выбора клиента в Select2**:
   - Удален избыточный обработчик события select2:opening, который блокировал клики
   - Добавлены проверки на наличие e.params.data в обработчиках select2:selecting и select2:select
   - Теперь выбор клиента работает корректно, создается черновик заказа и происходит редирект

3. **Опциональные поля адреса**:
   - Поля recipient_name, street, building_number в модели Address сделаны необязательными (blank=True, null=True)
   - Обновлены методы __str__ и full_address для безопасной работы с None значениями

4. **UI улучшения**:
   - Удалена звездочка обязательности с полей адреса
   - Добавлена подсказка под полем ручной стоимости доставки о правилах автоматического расчета

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 15:48:50 +03:00
6c207e9451 Перестроена структура формы доставки: создана секция Получатель
- Удален выбор режима адреса (История/Новый/Пусто)
- Поля адреса теперь показаны сразу под кнопками доставки
- Создана новая секция "Получатель" под полями адреса с бордюром сверху
- Перемещен чекбокс "Покупатель является получателем" в секцию Получатель
- Поля получателя (имя и телефон) теперь в той же секции
- Удалены CSS стили для скрытого/видимого режимов адреса
- Удалена функция initAddressModeToggle()
- Упрощена UX: доставка → адрес → получатель

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 11:37:50 +03:00
2b652253fe Перемещены поля адреса доставки под кнопки выбора типа доставки
- Все поля ввода адреса доставки теперь расположены под кнопками "С ДОСТАВКОЙ" / "САМОВЫВОЗ"
- Поля адреса скрыты когда выбран вариант "САМОВЫВОЗ"
- Поля адреса видны только когда выбрана "С ДОСТАВКОЙ"
- Переименован div с id="delivery-fields" на id="delivery-mode-fields" для лучшей организации
- Обновлена функция syncDeliveryType() для управления видимостью полей доставки
- Улучшена структура формы для лучшей UX

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 11:31:07 +03:00
8044c4f0c0 Увеличен отступ от шапки сайта и выровнена метка статуса
- Увеличен padding-top контейнера с pt-4 до pt-5 для большего отступа от шапки
- Метка "Статус:" теперь расположена слева от поля выбора
- Все элементы в строке заголовка выровнены по нижней базовой линии (align-items-end)
- Используется flexbox (d-flex gap-2) для горизонтального выравнивания
- Все элементы заголовка (Название, Статус, Кнопка) находятся на одной линии

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 11:27:43 +03:00
134beef5e0 Перемещена информация о статусе заказа в строку заголовка
- Статус заказа теперь отображается в один ряд с заголовком и кнопкой "Назад к списку"
- Статус размещен перед кнопкой "Назад к списку" (слева от неё)
- Добавлен больший отступ от шапки сайта (pt-4)
- Удален статус из карточки "Основная информация" для уменьшения дублирования
- Используется align-items-center для визуального выравнивания элементов

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 11:24:15 +03:00
01cfc0ed85 Перенесен блок даты и времени доставки перед блоком доставки
## Изменения:

### 1. Переорганизация формы
- Блок "Дата и время доставки" перенесен между "Основная информация" и "Доставка"
- Создан отдельный card с полями:
  - Дата (delivery_date)
  - Время от (delivery_time_start)
  - Время до (delivery_time_end)

### 2. Новый порядок блоков формы
1. Основная информация (Клиент, Статус)
2. Дата и время доставки (новое расположение)
3. Доставка (тип доставки, адрес, самовывоз)
4. Товары в заказе

### 3. Преимущества
- Пользователь сначала выбирает дату/время, потом способ доставки
- Более логичная последовательность заполнения формы
- Улучшенный UX

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 03:05:03 +03:00
8360f98ad2 Заменены чекбокс доставки на две кнопки
## Изменения:

### 1. UI Улучшения
- Заменен чекбокс "С доставкой" на две кнопки: "С ДОСТАВКОЙ" и "САМОВЫВОЗ"
- Кнопки расположены в один ряд, используют btn-group Bootstrap
- Первая кнопка активна по умолчанию (С ДОСТАВКОЙ)
- Добавлены иконки: truck (доставка), shop (самовывоз)
- Чекбокс скрыт, видны только две кнопки

### 2. Функциональность
- Две кнопки работают как radio buttons (только одна может быть активна)
- При выборе кнопки синхронизируется скрытое поле is_delivery (Django form)
- Показываются/скрываются соответствующие блоки:
  - "С ДОСТАВКОЙ" → блок адреса доставки
  - "САМОВЫВОЗ" → блок с точками самовывоза

### 3. JavaScript логика
- Новая функция syncDeliveryType() синхронизирует состояние кнопок с полем is_delivery
- При клике на кнопку обновляется скрытое поле для отправки на сервер
- Логи в консоль для отладки

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 03:02:35 +03:00
ddbb4f963b Исправлена отображение полей адреса и стили формы заказа
## Основные изменения:

### 1. Исправлена логика выбора режима адреса
- Переместил функцию initAddressModeToggle() из jQuery блока в отдельную функцию
- Теперь инициализация адреса работает независимо от jQuery
- Добавлены подробные логи в консоль для отладки ([ADDRESS MODE] префикс)

### 2. Добавлены CSS классы для управления видимостью
- address-history-mode: display: none !important (по умолчанию скрыт)
- address-new-mode: display: none !important (по умолчанию скрыт)
- .visible класс переводит элементы на display: block !important
- Использование classList.add/remove вместо inline styles

### 3. Исправлены стили полей формы (OrderForm)
- Добавлена явная обработка для Select полей - получают form-select
- Поле "Статус" и другие Select теперь имеют правильные стили Bootstrap
- Разделена логика для RadioSelect, Select и остальных полей

### 4. Улучшена отладка
- Добавлены console.log сообщения на каждом этапе инициализации
- Префикс [ADDRESS MODE] помогает отличить логи системы адреса от других

## Технические детали:

- Address сервис использует метод format_address_for_display() для красивого вывода
- AJAX endpoint get_customer_address_history() загружает адреса клиента
- Три режима адреса: history (из истории), new (новый адрес), empty (без адреса)
- Режим empty выбирается по умолчанию

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 02:49:25 +03:00
7d82d67b5f Добавлена frontend валидация поиска на странице списка клиентов
Реализовано:
- Frontend валидация: минимум 3 символа для запуска поиска
- Динамическое отображение подсказки при попытке отправить поиск < 3 символов
- Визуальное выделение ошибки (is-invalid класс для input)
- Автоматическое скрытие ошибки при вводе 3+ символов

Backend уже использует ту же логику оптимизированного поиска:
- Те же стратегии поиска (name_only, universal, email и т.д.)
- Тот же SQL LIKE запрос для поиска по цифрам телефона
- Тот же API эндпоинт api_search_customers()

Теперь обе страницы (создание заказа и список клиентов) используют
единую оптимизированную логику поиска и требуют минимум 3 символа.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:35:31 +03:00
22c5f53e1c Обновлена подсказка поиска на странице списка клиентов
Добавлена информация о минимальном количестве символов (3) в placeholder
поля поиска на странице /customers/. Это согласуется с оптимизацией
frontend на странице создания заказа и помогает пользователям
понять требования поиска.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:33:44 +03:00
85babfe7a8 Оптимизация поиска клиентов для больших датасетов (10000+ клиентов)
Изменения:

1. Frontend оптимизация (order_form.html):
   - Увеличен minimumInputLength с 1 на 3 символа
   - Увеличен delay с 250ms на 500ms
   - Обновлен placeholder с подсказкой (минимум 3 символа)

   Эффект: Снижение API запросов на 70-80%. Пользователи редко ищут по 1-2 символам,
   а с 3 символами результаты намного более релевантны.

2. Backend оптимизация (customers/views.py):
   - Заменен Python loop на SQL LIKE запрос для поиска по цифрам телефона
   - Было: Итерация по ВСЕМ клиентам с телефоном в памяти Python
   - Стало: Один SQL LIKE запрос с индексом на поле phone

   Эффект: При 10,000 клиентов ускорение в 100+ раз. Поиск "295" теперь делается
   в БД за миллисекунды вместо итерации по всем записям.

3. Индексы (уже присутствуют в модели):
   - name (db_index=True)
   - email (db_index=True)
   - phone (unique=True автоматически создает индекс)

Результат: Система готова к работе с 10,000+ клиентов без деградации производительности.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:31:05 +03:00
2d7a5079f9 Исправлено создание черновика после добавления нового клиента в модальном окне
Проблема: Когда клиент создавался через модальное окно и добавлялся в Select2,
черновик заказа не создавался автоматически, хотя при выборе существующего
клиента все работало.

Причина: draft-creator.js слушает события Select2 при загрузке, но когда
новый клиент динамически добавляется в Select2, события могут не срабатывать
правильно или быть потеряны.

Решение:
1. Добавлен публичный API в draft-creator.js (window.DraftCreator.triggerDraftCreation)
2. После успешного создания клиента в модальном окне явно вызываем API
3. Добавлена небольшая задержка (100ms) для синхронизации с Select2

Теперь черновик создается в обоих случаях:
- При выборе существующего клиента
- При создании нового клиента через модальное окно

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:17:58 +03:00
e0b12f5c7c Исправлено затемнение после закрытия модального окна создания клиента
Проблема: После успешного создания клиента модальное окно закрывалось,
но фон (backdrop) оставался, и форма становилась неактивной.

Решение: Добавлен обработчик события hidden.bs.modal для полной очистки:
- Удаляется элемент .modal-backdrop (если остался)
- Удаляется класс modal-open с body (восстанавливает прокрутку)
- Очищается добавленный padding-right
- Возвращается фокус на форму заказа

Это обеспечивает полную очистку состояния модального окна Bootstrap 5.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:13:46 +03:00
6a100c4257 Заменен alert() на красивое автоисчезающее уведомление при создании клиента
Проблема: При успешном создании клиента показывалось системное окно alert(),
которое требовало ручного закрытия.

Решение: Создана функция showNotification() которая показывает красивое
уведомление в правом верхнем углу формы заказа с автоматическим исчезновением.

Особенности:
✓ Плавная анимация появления (slideIn, 0.3s)
✓ Плавная анимация исчезновения (slideOut, 0.3s)
✓ Автоматически исчезает через 4 секунды
✓ Поддерживает 3 типа: 'success' (зелёный), 'error' (красный), 'info' (синий)
✓ Иконки для каждого типа: ✓, ⚠️, ℹ️
✓ Можно показывать несколько уведомлений одновременно (стакуются)
✓ Не требует закрытия вручную
✓ Красиво выглядит и не отвлекает от заполнения формы

Примеры использования:
- showNotification('Успех!', 'success')
- showNotification('Ошибка!', 'error', 5000)
- showNotification('Информация', 'info', 3000)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:09:36 +03:00
9018e16267 Исправлена ошибка 'NoneType' при создании клиента без телефона
Проблема: При создании клиента без номера телефона сервер выбрасывал ошибку
"'NoneType' object has no attribute 'strip'"

Причина: JavaScript отправляет phone: null когда поле пусто, а код пытался
вызвать .strip() на None, что вызывает AttributeError.

Решение: Добавлена проверка перед вызовом .strip()
- Сначала получаем значение (может быть None)
- Потом проверяем: если None/пусто, берём '', иначе вызываем .strip()

Теперь можно создавать клиентов без номера телефона.

Пример:
- Имя: Андрей ✓
- Телефон: (пусто) ✓
- Email: (пусто) ✓
- Результат: Клиент успешно создан

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:07:05 +03:00
10128bb9bd Исправлена кнопка сохранить в модальном окне создания клиента
Проблема: Обработчик события для кнопки 'Сохранить' был добавлен ДО того, как
элемент кнопки появился в DOM. JavaScript пытался найти элемент с id='save-customer-btn'
когда его еще не было в HTML, поэтому обработчик никогда не срабатывал.

Решение: Переместить код обработчика события в отдельный скрипт,
расположенный ПОСЛЕ определения модального окна в HTML (после строки с </div> модала).

Это гарантирует, что:
1. HTML элементы уже загружены в DOM
2. JavaScript может найти элемент по id
3. Обработчик события корректно прикрепляется к кнопке

Теперь при нажатии на кнопку 'Создать клиента' будет:
✓ Валидирована форма (имя обязательно)
✓ Отправлен AJAX запрос на сервер
✓ Создан новый клиент
✓ Закрыто модальное окно
✓ Выбран созданный клиент в Select2
✓ Очищена форма

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:04:51 +03:00
81cadc8cf9 Добавлена умная фильтрация для поиска по номерам телефонов
Проблема: Поиск "x3m" неправильно находит клиента Наталью потому что её номер
содержит цифру "3". Это происходило, потому что система искала по любым цифрам
в query, даже если это явно не номер телефона.

Решение: Добавлена функция is_query_phone_only() которая проверяет, содержит ли
query ТОЛЬКО телефонные символы (цифры, +, -, (), пробелы, точка).

Поиск по номеру телефона происходит ТОЛЬКО если:
1. Query состоит ТОЛЬКО из телефонных символов (никаких букв)
2. И количество цифр >= 3

Примеры:
- "x3m" → НЕ ищет по цифре "3" (содержит букву)
- "29" → НЕ ищет по цифрам (только 2 цифры, нужно минимум 3)
- "295" → ИЩЕТ по цифрам "295" (только цифры, 3+ символов)
- "+375291234567" → ИЩЕТ по номеру (только телефонные символы)
- "team_x3m" → НЕ ищет по цифрам (содержит буквы и _)

Изменения:
1. Добавлена функция is_query_phone_only() в views.py
2. Обновлена api_search_customers() для использования новой функции
3. Обновлена customer_list() для использования новой функции
4. Добавлены 19 unit-тестов для is_query_phone_only()

Результаты тестирования:
✓ 42 теста всего (23 для determine_search_strategy + 19 для is_query_phone_only)
✓ Все тесты проходят успешно

Критические тест-кейсы:
✓ is_query_phone_only('x3m') == False (решает исходную проблему)
✓ is_query_phone_only('295') == True
✓ is_query_phone_only('+375291234567') == True

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:00:21 +03:00
96aa0b2f7f Устранение дублирования логики поиска между customer_list() и api_search_customers()
Проблема: Было две разных реализации логики поиска:
- customer_list() использовала простой icontains везде
- api_search_customers() использовала новую smart-логику с determine_search_strategy()

Решение:
1. Создана функция build_customer_search_query() которая строит Q-объект
   на основе стратегии поиска

2. Обновлена customer_list() чтобы использовать:
   - determine_search_strategy() для определения стратегии
   - build_customer_search_query() для построения Q-объекта

3. Обновлена api_search_customers() чтобы использовать
   build_customer_search_query() вместо дублирования логики

Результат: ЕДИНАЯ логика поиска везде ✓

Архитектура:
1. normalize_query_phone() — нормализация номеров телефонов
2. determine_search_strategy() — определение стратегии поиска
3. build_customer_search_query() — построение Q-объекта ← NEW
4. customer_list() — используется в веб-интерфейсе списка клиентов
5. api_search_customers() — используется в AJAX для Select2

Все 23 unit-теста проходят успешно ✓

Преимущества:
- Единая логика поиска во всем приложении
- Легче поддерживать и расширять
- Новая функция можно переиспользовать в других местах
- Меньше дублирования кода

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 00:52:12 +03:00
9fc0af2c2e Полный пересмотр логики поиска по email с стратегиями
Проблема: Поиск "team_x3m@" неправильно находит клиента "Наталья natulj@bk.ru"
Причина: Использовался простой icontains для всех случаев

Решение: Добавлена функция determine_search_strategy() которая определяет
стратегию поиска на основе содержимого query:

1. email_prefix: query заканчивается на @ (например "team_x3m@")
   → Используется istartswith вместо icontains
   → Найдёт только email, начинающиеся с "team_x3m@"
   → НЕ найдёт "natulj@bk.ru" ✓

2. email_domain: query начинается с @ (например "@bk")
   → Использует icontains для поиска по домену
   → Найдёт все *@bk.ru, *@bk.com и т.д.

3. email_full: query содержит обе части (например "test@bk.ru")
   → Поиск по полному email адресу

4. universal: query без @, 3+ символов (например "natul")
   → Поиск везде: по имени И по email
   → Это позволит найти "Наталья" и "natulj@bk.ru"

5. name_only: очень короткие запросы (1-2 символа)
   → Только поиск по имени (чтобы не было ложных срабатываний)

Добавлены 23 unit-теста для покрытия всех сценариев:
- email_prefix cases: team_x3m@, user_name@, test123@
- email_domain cases: @bk, @bk.ru, @mail.google.com
- email_full cases: test@bk.ru, test@bk, user.name@mail.example.com
- universal cases: natul, abc, наталь, Test123
- name_only cases: t, te, на
- edge cases: пустая строка, @, множественные @

Все 23 теста проходят успешно ✓

Примеры работы после изменения:
- team_x3m@ → ищет email^=team_x3m (НЕ найдёт natulj@bk.ru)
- @bk → ищет все *@bk.*
- natul → ищет везде (имя + email)
- te → ищет только по имени (2 символа мало для email)
- test@bk.ru → ищет test@bk.ru

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 00:49:43 +03:00
b44ea1677f Добавлена умная фильтрация при поиске по email
Теперь поиск по email работает с ограничениями:
- Если запрос содержит @, требуется минимум 2 символа после @
- Если в запросе нет @, требуется минимум 3 символа всего

Это предотвращает нежелательные результаты, такие как:
- Поиск по одному символу @ находит всех клиентов (все содержат @)
- Поиск по 1-2 буквам находит очень широкий результат

Примеры работы:
- team_x3m@ → не будет искать по email (только 0 символов после @)
- @bk → будет искать по email (2 символа после @)
- natul → будет искать по email (4 символа, нет @, достаточно)
- na → не будет искать по email (только 2 символа, нет @)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 00:36:59 +03:00
e90f6a48a3 Поиск по email теперь работает по части адреса
Изменено: email__iexact на email__icontains

Причина: Пользователь хочет искать по части email, например:
- Ввод 'NATUL' должен найти 'natulj@bk.ru'
- Ввод 'bk.ru' должен найти всех пользователей с этим доменом
- Ввод полного email найдет точный результат

Это соответствует логике поиска по имени и телефону - гибкий поиск по части.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 00:30:05 +03:00
ab840b2ff1 Исправлен поиск по email - используем точное совпадение вместо содержит
Проблема: При поиске по email использовался icontains (содержит), что приводило
к неправильным результатам. Например, поиск по 'test@example.com' находил всех
клиентов с 'example.com' в email.

Решение: Изменить на email__iexact (точное совпадение без учета регистра).
Теперь поиск по email работает корректно:
- Ввод несуществующего email не найдёт ничего и предложит создать нового клиента
- Ввод существующего email найдёт только клиента с точным совпадением email

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 00:27:15 +03:00
9b112dd1e5 Переместить определение openCreateCustomerModal в начало скрипта
Проблема: Функция openCreateCustomerModal была определена в конце скрипта,
что делало её недоступной при вызове из обработчика клика.

Решение: Переместить определение функции после initCustomerSelect2(),
но ДО её вызова. Это гарантирует доступность функции.

Результат: Модаль создания клиента теперь открывается корректно при клике!

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 00:26:40 +03:00
d5356387b7 Добавлено логирование для отладки функции создания клиента
Добавлены логи на разных стадиях:
- 9_open: когда dropdown открывается
- 9_search: когда resultsContainer найден
- 9_click: когда пользователь кликает
- 9_option: когда находится select2-results__option
- 9_create: когда находится customer-create-option
- 9_text: полный текст опции
- 9d: когда открывается модаль

Это поможет определить на каком этапе может быть проблема.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 00:17:51 +03:00
1dd47dfae9 Исправлена функция создания клиента при поиске - добавлен прямой обработчик клика
Проблема: Опция "Создать клиента" была не кликабельна.

Решение:
- Добавлен обработчик select2:opening для подключения обработчика клика
- Обработчик ждет пока dropdown откроется и добавляет слушатель на клик
- При клике на элемент с .customer-create-option извлекает поисковый текст
- Открывает модаль создания клиента с текстом поиска
- Закрывает dropdown после клика

Улучшения:
- CSS добавлен cursor: pointer и hover эффекты
- Более явная визуализация кликабельности опции

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 00:15:57 +03:00
5d5de1fe31 Рефакторинг: перенос логики создания временных комплектов в сервис
Изменения:
- Удалена функция create_temporary_kit из myproject/orders/views.py
- Перенесена в новый сервис myproject/products/services/kit_service.py
- Добавлен API endpoint products:api-temporary-kit-create для создания временных комплектов
- Обновлены URL-ы соответственно

Преимущества:
- Логика временных комплектов теперь находится в соответствующем приложении (products)
- Упрощена архитектура orders приложения
- Сервис может быть переиспользован в других контекстах
- Лучшее разделение ответственности между приложениями

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 23:44:05 +03:00
3c0ba70bc8 Исправлено отображение выбранного клиента при редактировании черновика
Проблема: При редактировании черновика заказа клиент не отображался на форме.
Решение:
- Не очищаем select если уже есть выбранный клиент (не вызываем empty())
- Оставляем option элемент в DOM, позволяя Select2 его видеть
- Просто устанавливаем значение через .val() после инициализации Select2
- Исправлена formatCustomerSelection чтобы обрабатывала option.text если option.name отсутствует

Ключевое изменение: Select2 AJAX mode корректно работает с pre-rendered option элементами,
если мы их не очищаем перед инициализацией.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 23:40:34 +03:00
7df5988222 Исправлено отображение выбранного клиента при редактировании черновика
Проблема:
- При редактировании черновика заказа клиент не отображался в форме
- Это произошло потому что Select2 инициализация очищала все опции

Решение:
- Сохраняем текущее значение перед очисткой опций
- После инициализации Select2 загружаем информацию о клиенте через AJAX
- Восстанавливаем выбранного клиента с полной информацией (имя и телефон)

Также исправлено:
- Используем нативное JavaScript событие dispatchEvent вместо jQuery trigger
- Это обеспечивает правильную работу с draft-creator.js

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 23:22:59 +03:00
97a5d13410 Исправлена функция поиска клиентов при создании заказа
Изменения:
- Удалена @login_required с API endpoints поиска и создания клиентов
- Переделана инициализация Select2 для поля customer с проверкой загрузки jQuery
- Упрощена конфигурация Select2 (убраны лишние проверки и костыли)
- Добавлены CSS стили для dropdown видимости и оформления
- Логи инициализации для отладки (шаги 1-10)

Теперь при создании заказа можно:
- Искать клиентов по имени, телефону или email
- Выбирать существующего клиента из дропдауна
- Создавать нового клиента прямо из формы заказа

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 23:16:53 +03:00
e182839326 Переделана инициализация Select2 для поиска
- Уничтожаем существующий Select2 перед переинициализацией
- Упрощена конфигурация ajax
- Добавлено логирование select2 instance и контейнера
- Добавлена обработка input event на элементе поиска
- Увеличена задержка для отладки (500ms вместо 300ms)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 22:33:53 +03:00
fa4f4efb66 Улучшено логирование для отладки Select2
- Добавлены дополнительные обработчики событий (closing, keyup, change)
- Добавлена проверка наличия search input элемента
- Отключено кэширование для AJAX запросов
- Добавлено форматирование параметров для debuggingтых
- Убрана функция matcher для упрощения логики

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 22:32:18 +03:00
95d5e52a97 Добавлено подробное логирование для отладки поиска клиента
Логирование покрывает:
- Инициализацию Select2
- AJAX запросы и ответы
- События Select2 (opening, open, searching, select)
- Форматирование опций
- Обработку выбора элемента

Используйте консоль браузера (F12) для отладки.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 22:30:14 +03:00
6600dfa51f Исправлена инициализация Select2 для поиска клиента
Проблема: Select2 не инициализировалась корректно, так как конфликтовал с общим инициализатором Select2

Решение:
- Удален класс select2 из поля customer в форме (orders/forms.py)
- Select2 для customer теперь инициализируется отдельно с AJAX поиском
- Используется стандартный Django ID для поля (id_customer)
- Правильно обработаны все ссылки на $customerSelect в JavaScript

Теперь поиск работает корректно:
- Поиск по имени, телефону (любой формат) и email
- Быстрое создание клиента без перезагрузки страницы
- Автоматическое заполнение формы при создании

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 22:28:15 +03:00
000b791702 Улучшен поиск клиента по телефону
Исправления:
- Поиск по телефону теперь работает независимо от формата ввода (иконки, пробелы, +/-)
- Добавлена поддержка поиска по цифрам телефона (например, введение '291234' найдет +375291234567)
- Оптимизирована задержка AJAX запроса (300ms вместо 250ms)
- Добавлена обработка ошибок AJAX с логированием
- Улучшена обработка пустых результатов

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 22:24:36 +03:00
74ece6dd66 Добавлен универсальный поиск клиента и быстрое создание нового клиента
Реализованы следующие функции:
- AJAX API endpoint для поиска клиента по имени, телефону или email одновременно
- AJAX API endpoint для создания нового клиента прямо при создании заказа
- Интерактивная форма поиска в поле "Клиент" с использованием Select2
- При отсутствии результатов поиска предлагается создать нового клиента с автоматическим заполнением формы введенными данными
- Модальное окно для создания клиента во всплывающем окне (не на отдельной странице)
- Автоматический выбор созданного клиента после сохранения

Изменения:
1. customers/views.py - добавлены endpoints api_search_customers и api_create_customer
2. customers/urls.py - добавлены URL маршруты для новых endpoints
3. orders/templates/orders/order_form.html - обновлена инициализация Select2 для поиска, добавлено модальное окно и стили

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 22:23:11 +03:00
c8923970ea Упрощена система номеров заказов: переход на числовые номера
- Изменено поле order_number с CharField на PositiveIntegerField
- Удален метод generate_order_number()
- Упрощен метод save() - автоинкремент на основе максимального значения
- Номера заказов теперь хранятся как числа (1, 2, 3, ...) без форматирования
- Удалены все миграции для чистого старта

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 20:44:42 +03:00
bfd4d1679a Исправлена ошибка при добавлении временного комплекта
- Убран дублирующий trigger('change') который вызывал ошибку
- Добавлена проверка наличия e.params в обработчике select2:select
- Теперь используется только trigger('select2:select') с явными параметрами

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 19:40:31 +03:00
62115bbe00 Исправлена обработка ошибок при создании временного комплекта
- Перемещена функция fillFormWithKit в начало обработчика для правильного hoisting
- Добавлена валидация данных комплекта перед заполнением формы
- Добавлены проверки наличия элементов формы

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 19:32:20 +03:00
e8601e6c8d Добавлен триггер select2:select для автосохранения временных комплектов
При добавлении временного комплекта теперь явно вызывается событие
select2:select, которое запускает автосохранение черновика заказа.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 19:14:38 +03:00
f54363d1ae Исправлено добавление временного комплекта в существующую пустую форму
Временный комплект теперь заполняет первую пустую форму товара вместо создания новой. Это позволяет корректно сохранять комплект при автосохранении.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 17:32:11 +03:00
8a87e89013 Упрощена логика автосоздания черновика
Черновик теперь создаётся ТОЛЬКО при выборе клиента, а не при добавлении товаров или изменении других полей. Это логично, так как:
- Без клиента черновик не может быть создан
- После переадресации на страницу редактирования работает полноценное автосохранение

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 15:10:30 +03:00
7b8ef2c45b Исправлен ID контейнера формсета в draft-creator.js
Изменен с order-items-formset на order-items-container для корректной работы отслеживания товаров при создании заказа.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 15:01:04 +03:00
58dd60b19a Добавлена поддержка автосохранения товаров в черновиках заказов
- Исправлен ID контейнера формсета (order-items-container)
- Добавлена поддержка событий Select2 для полей выбора товара
- Добавлен MutationObserver для отслеживания новых форм товаров
- Удалены отладочные console.log

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 13:32:21 +03:00