Commit Graph

65 Commits

Author SHA1 Message Date
7132d2c910 feat: Замена is_active на status для архивирования товаров
Реализована трёхуровневая система статусов товаров и комплектов:
- active (Активный) - товар доступен для продажи
- archived (Архивный) - скрыт, можно восстановить в следующем сезоне
- discontinued (Снят) - морально устарел, готов к удалению

Изменения:
1. Модели (BaseProductEntity, Product, ProductKit):
   - Заменено поле is_deleted (Boolean) на status (CharField)
   - Добавлены архивные метаданные (archived_at, archived_by)
   - Обновлены методы: archive(), restore(), discontinue(), delete()
   - Уникальное ограничение изменено на conditional (status='active')

2. Менеджеры (ActiveManager, SoftDeleteQuerySet):
   - Полиморфная поддержка обеих систем (status и is_active)
   - Использует hasattr() для совместимости с наследниками
   - Методы: archive(), restore(), discontinue(), archived_only(), active_only()

3. Формы (ProductForm, ProductKitForm):
   - Включены поле status в формы
   - Валидация уникальности по status='active'
   - CSS классы для статус-селектора

4. Admin панель:
   - DeletedFilter переименован в StatusFilter с тремя опциями
   - get_status_display() с цветным отображением статуса
   - Actions: restore_items, hard_delete_selected, delete_selected
   - Readonly поля для архивирования

5. Представления:
   - ProductListView: фильтр status вместо is_active
   - CombinedProductListView: поддержка фильтра status для товаров и комплектов
   - API views обновлены для работы со статусом

6. Шаблоны:
   - product_form.html: form.status вместо form.is_active
   - productkit_create.html: form.status вместо form.is_active
   - productkit_edit.html: form.status вместо form.is_active

7. Миграции:
   - Удалены все старые миграции (чистый перезапуск по требованию пользователя)
   - Создана новая миграция 0001_initial с полной структурой status-системы
   - Удален старый код преобразования is_deleted -> status

Проведённые проверки:
- Django system check passed ✓
- Полиморфные менеджеры работают с обеими системами
- Уникальные ограничения корректно работают с условиями
- История заказов сохраняется даже после архивирования товара (django-simple-history)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 15:30:23 +03:00
079bd23829 feat: Добавить трёхуровневую защиту от дубликатов имён товаров, категорий, тегов и комплектов
Реализована полная система обеспечения уникальности названий:

1. **Уровень БД (Model Constraints)** - добавлены UniqueConstraint для:
   - Product: уникальность имени среди активных товаров
   - ProductCategory: уникальность имени среди активных категорий
   - ProductTag: уникальность имени только для активных тегов (неактивные могут повторяться)
   - ProductKit: уникальность имени среди активных, непроизвременных комплектов

2. **Уровень формы (Form Validation)** - добавлены clean() методы для:
   - ProductForm, ProductKitForm, ProductCategoryForm, ProductTagForm
   - Валидация до попытки сохранения в БД
   - Сохранение введённых данных при ошибке валидации

3. **Уровень представления (IntegrityError Handling)** - добавлена обработка в views:
   - ProductCategoryCreateView, ProductCategoryUpdateView
   - ProductTagCreateView, ProductTagUpdateView
   - ProductKitCreateView, ProductKitUpdateView
   - create_tag_api: защита от race conditions с fallback поиском

Три уровня защиты гарантируют:
- Профилактика ошибок на уровне формы
- Обработка исключительных ситуаций в views
- Защита БД от одновременных запросов (race conditions)
- Пользователь видит понятное сообщение об ошибке вместо 500 ошибки

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 13:49:52 +03:00
0b41c6815c feat: Изменить нумерацию позиций фотографий на 1-based для пользователя
Изменена отображение нумерации позиций фотографий товара:
- Главное фото теперь показывается как " Главное (позиция 1)" вместо "Главное"
- Остальные фотографии нумеруются с 2 вместо 1: "Позиция 2, 3, 4..."
- Это совпадает с интуитивным восприятием пользователя (первая позиция = главное фото)

Изменено:
1. product_detail.html (2 места):
   - Отображение в галерее миниатюр
   - Отображение в модальной галерее (бейдж главного фото)

2. product_form.html (1 место):
   - Отображение позиции при редактировании товара

Внутренняя база данных не изменяется (order = 0,1,2...) - это только визуальное отображение.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 12:43:16 +03:00
0bdb42401a fix: Обработка race condition при дублировании slug товаров
Реализована трёхуровневая защита от IntegrityError при создании товаров с одинаковым названием:

1. SlugService улучшен:
   - Добавлен метод _get_base_queryset() для работы с мягким удалением
   - Проверка всех объектов включая удалённые (all_objects)
   - Новый метод get_next_available_slug() для retry обработки
   - Максимум 100 попыток поиска уникального slug

2. BaseProductEntity.save() защищена:
   - transaction.atomic() для атомарности операции
   - Retry логика с 5 попытками при IntegrityError
   - При конфликте добавляется суффикс (-1, -2, -3...)
   - Fallback на timestamp если суффиксы исчерпаны

3. Views обрабатывают IntegrityError:
   - ProductCreateView.form_valid() перехватывает ошибку
   - ProductUpdateView.form_valid() перехватывает ошибку
   - Пользователю показывается дружелюбное сообщение об ошибке
   - Нет 500 ошибок - вместо этого form_invalid() с сообщением

Эффект:
- До: User создаёт товар "Роза красная" 2 раза → IntegrityError → 500 ошибка
- После: User создаёт товар "Роза красная" 2 раза → slug автоматически становится "roza-krasnaya-1"

Протестировано на Django shell и синтаксис проверен.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 11:57:11 +03:00
d9903cd721 feat: Улучшена система сообщений об ошибках и предупреждениях
Изменения:
- ProductCreateView/UpdateView теперь показывают warnings для предупреждений о лимите фото
- Разделение сообщений: error (красный) vs warning (желтый)
- Улучшен components/messages.html:
  * Добавлены иконки для каждого типа сообщения
  * Bootstrap Icons интеграция
  * Кастомные цвета для alerts
  * Лучший visual feedback для пользователя

Теперь пользователи видят понятные сообщения везде на сайте!

🤖 Generated with Claude Code
2025-11-15 11:27:08 +03:00
f7d1851418 fix: Сохранять первые 10 фото, остальные отклонять с уведомлением
Изменено поведение handle_photos():
- Если загружено больше 10 фото, сохраняются первые 10
- Остальные отклоняются с warning сообщением
- Товар теперь ВСЕГДА создается (даже если больше 10 фото)

Это позволяет пользователю загрузить 11+ фото,
но система обработает только первые 10 и уведомит об этом.

🤖 Generated with Claude Code
2025-11-15 11:20:51 +03:00
0791ebb13b fix: Сохранять файл фото ДО запуска Celery task
При асинхронной обработке фото нужно сначала сохранить файл в БД,
потом запустить Celery task. Иначе task не найдет файл.

Изменения:
- BasePhoto.save() теперь сохраняет файл перед запуском task
- Исправлена проблема 'Photo has no image file' в Celery worker

🤖 Generated with Claude Code
2025-11-15 11:11:08 +03:00
4a4bd437b9 refactor: Заменить сущность Магазин (Shop) на Склад (Warehouse)
Упрощена логика системы путём замены отдельной сущности "Магазин"
на универсальную сущность "Склад", которая может использоваться
как точка самовывоза.

Изменения:
- Расширена модель Warehouse: добавлены адрес, контакты, флаг is_pickup_point
- Модель Order: поле pickup_shop заменено на pickup_warehouse
- Обновлены все формы, сервисы, views, admin для работы со складами
- Обновлены шаблоны HTML и JavaScript код
- Удалено приложение shops полностью
- Пересозданы миграции БД
- Обновлён навбар (удалена ссылка на магазины)

Преимущества:
- Упрощена архитектура системы
- Единая точка управления складами и точками самовывоза
- Интеграция с системой инвентаризации

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 23:50:30 +03:00
c7875f147c Implement flexible order status management system
Features:
- Created OrderStatus model for managing statuses per tenant
- Added system-level statuses: draft, new, confirmed, in_assembly, in_delivery, completed, return, cancelled
- Implemented CRUD views for managing order statuses
- Created OrderStatusService with status transitions and business logic hooks
- Updated Order model to use ForeignKey to OrderStatus
- Added is_returned flag for tracking returned orders
- Updated filters to work with new OrderStatus model
- Created management command for status initialization
- Added HTML templates for status list, form, and confirmation
- Fixed views.py to use OrderStatus instead of removed STATUS_CHOICES

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 16:29:50 +03:00
46578382b0 Улучшения в моделях заказов и комплектов
## Изменения:

### 1. ProductKit - расчет цены для вариантов товаров
- Добавлена обработка variant_group в методах расчета base_price
- Теперь учитываются варианты товаров при расчете стоимости комплекта

### 2. DraftOrderService - упрощение логики автосохранения
- Удалена проверка is_draft() при обновлении (позволяет обновлять заказы в других статусах)
- Улучшена документация метода update_draft

### 3. Шаблоны и скрипты
- Обновлены шаблоны форм создания/редактирования комплектов
- Обновлены скрипты автосохранения

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 11:34:06 +03:00
77064a274f Реализовано управление активностью тегов товаров и комплектов
## Что сделано:

### 1. Фильтрация тегов по активности
- ProductForm и ProductKitForm показывают только активные теги в селектах
- ProductListView, ProductKitListView передают только активные теги в контекст фильтров

### 2. Отображение тегов на страницах товаров/комплектов
- product_detail.html отображает только активные теги
- productkit_detail.html отображает только активные теги

### 3. Логика отображения в деталях тега
- Для активного тега: показываются только активные товары/комплекты
- Для неактивного тега: показываются ВСЕ товары/комплекты (для возможности ручной очистки)

### 4. API endpoint для переключения статуса
- Новый endpoint toggle_tag_status_api в api_views.py
- POST /products/api/tags/<id>/toggle/
- Переключает is_active и возвращает новый статус

### 5. AJAX toggle switch в таблице тегов
- Заменены бейджи на toggle switch в tag_list.html
- Переключатель в 1.3x больше (масштабирование через CSS)
- Мгновенное обновление без перезагрузки страницы
- Показывает сообщение об успехе/ошибке

### 6. Связь в БД остаётся неизменной
- При деактивации тег остаётся привязан к товарам в БД
- Просто скрывается в интерфейсе
- При реактивации вновь становится видимым

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 11:33:12 +03:00
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
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
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
848b6b1574 Удалены все ссылки на несуществующее поле 'notes' в KitItem
Проблема:
- Поле 'notes' было удалено из модели KitItem миграцией 0005
- Админка и другие части кода продолжали ссылаться на это поле
- Это вызывало FieldError при попытке редактирования ProductKit в админке

Решение:
Удалены все 6 упоминаний поля 'notes' из кода:

1. admin.py (2 места):
   - KitItemInline: удалено 'notes' из fields
   - KitItemAdmin: удалено 'notes' из fields

2. productkit_detail.html (2 места):
   - Удален заголовок колонки "Примечание"
   - Удален блок отображения item.notes

3. demo_variants.py (2 места):
   - Удалено 'notes' из defaults для премиум букета
   - Удалено 'notes' из defaults для эконом букета

Результат:
- Админка ProductKit теперь работает корректно
- Шаблоны не обращаются к несуществующим полям
- Демо-команды создания вариантов работают без ошибок

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 16:50:16 +03:00
deb138f037 Исправлен импорт ProductKitMakePermanentView
Добавлен ProductKitMakePermanentView в:
- products/views/__init__.py импорты
- __all__ экспорт

Теперь view доступен через products.views и сервер запускается без ошибок.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 15:29:25 +03:00
a1df188b2a Реализовано преобразование временных комплектов в постоянные
Views (products/views/productkit_views.py):
- ProductKitMakePermanentView: view для преобразования временного комплекта
  * Доступен только для временных комплектов (is_temporary=True)
  * Позволяет отредактировать название, описание, категории, теги, цену
  * Вызывает метод make_permanent() модели
  * Перенаправляет на детальную страницу комплекта после успеха

URLs (products/urls.py):
- /products/kits/<pk>/make-permanent/ - страница преобразования

Templates:
- productkit_make_permanent.html: форма преобразования с составом и ценой
- order_detail.html: добавлена кнопка "Сделать постоянным" для временных комплектов

Теперь флорист может:
1. Увидеть временный комплект в заказе с badge "Временный"
2. Нажать "Сделать постоянным"
3. Отредактировать название, добавить категории
4. Сохранить - комплект появится в каталоге

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 15:19:56 +03:00
ea4bb5a43b Скрыты временные комплекты из каталога и поиска
Views:
- ProductKitListView: фильтр is_temporary=False
- CombinedProductListView: фильтр is_temporary=False для комплектов
- API search: фильтр is_temporary=False в поиске и популярных

Admin:
- Добавлен фильтр по is_temporary
- Добавлено отображение статуса временного комплекта в списке
- Добавлена ссылка на заказ для временных комплектов
- Добавлен раздел "Временный комплект" в fieldsets

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

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 15:00:25 +03:00
7b78ad2a6e Добавлена поддержка временных комплектов в модель ProductKit
- Добавлено поле is_temporary для пометки временных комплектов
- Добавлено поле order для связи с заказом
- Добавлены индексы для производительности
- Добавлен метод make_permanent() для преобразования в постоянный комплект

Временные комплекты создаются для конкретных заказов и не показываются
в общем каталоге, но хранятся в БД для истории и анализа.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:59:09 +03:00
ec0557c8cf feat: Добавлена функциональность управления заказами и улучшен поиск товаров
Заказы:
- Добавлены миграции для исторических записей с полями оплаты и получателя
- Расширен admin для заказов с инлайнами товаров/комплектов
- Реализованы представления списка, создания, редактирования и удаления заказов
- Добавлен шаблон подтверждения удаления заказа
- Настроены URL-маршруты для работы с заказами

Клиенты:
- Добавлена миграция с новыми полями адресов и подтверждений
- Обновлена модель клиентов с дополнительными полями
- Улучшен admin для работы с клиентами

Товары:
- Значительно улучшен API поиска товаров с поддержкой фильтрации
- Добавлен Select2 виджет для динамического поиска товаров
- Создан статический JS файл для интеграции Select2
- Оптимизирована обработка запросов и ответов API

Прочее:
- Добавлены новые настройки в settings.py
- Обновлена навигация в navbar.html
- Обновлены URL-маршруты проекта

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 16:10:19 +03:00
9e430bca18 refactor: оптимизирована обработка цен и запросов в группах вариантов
Улучшения:
- Исправлена отображение цены в таблице вариантов: заменено sale_price на actual_price
  чтобы правильно обрабатывать случаи когда скидка не установлена
- Оптимизирован property in_stock: вычисляется в памяти из prefetched данных
  вместо отдельного запроса EXISTS к БД
- Оптимизирован property price: использует actual_price (sale_price или price)
  вместо только sale_price, добавлена документация о требовании prefetch_related
- Оптимизирован DetailView.get_context_data: используется кешированный
  prefetch_related вместо создания нового queryset для items
- Исправлена AJAX функция _get_items_data: использует actual_price вместо sale_price

Результат:
- Исчезла проблема с выводом "None" вместо цены
- Сокращено количество запросов к БД с 4-5 до 3 для страницы detail
- Улучшена производительность при работе с группами вариантов

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 08:02:43 +03:00
706ee5d8e8 fix: Удалить поле примечание из JS шаблонов динамического добавления товаров
Удалено поле примечание из JavaScript шаблонов в:
- productkit_create.html (строки 797-802)
- productkit_edit.html (строки 813-818)

Эти шаблоны используются при динамическом добавлении нового товара в комплект
через кнопку 'Добавить товар'.

Раньше это поле было скрыто в обычном template include, но осталось в JS коде,
что приводило к отображению примечания при добавлении нового товара.

Теперь поле примечания полностью удалено из всех частей приложения.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 22:32:33 +03:00
7506fee20a feat: Удалить поле примечание из компонентов комплектов
Удалено ненужное поле 'notes' из формы создания/редактирования комплектов:
- Удалено из модели KitItem
- Удалено из формы KitItemForm
- Удалено из template kititem_formset.html
- Удалено из formset'ов KitItemFormSetCreate и KitItemFormSetUpdate
- Создана миграция БД для удаления поля из базы данных

Теперь каждый товар в комплекте отображается с 4 полями:
- Товар (или Группа вариантов)
- Количество
- Кнопка удаления
- ID (скрытое)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 21:08:41 +03:00
c7bf23c79c fix: Улучшить загрузку сохранённых значений корректировки цены на странице редактирования
Исправлена критическая проблема, когда сохранённые значения корректировки цены не отображались
надёжно на странице редактирования (отображались только в 1 из 10 случаев).

Причина проблемы:
- При загрузке значений в поля input, срабатывают события input/change
- Эти события вызывают calculateFinalPrice() и validateSingleAdjustment()
- calculateFinalPrice() перезаписывает скрытые поля со значениями по умолчанию

Решение:
- Добавлен флаг isLoadingAdjustmentValues для подавления событий input/change
- Во время загрузки значений: флаг = true, события игнорируются
- После загрузки: флаг = false, события обрабатываются нормально
- Использование requestAnimationFrame для более надёжной синхронизации

Файлы изменены:
- productkit_edit.html (добавлены флаги и логика подавления событий)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 20:10:52 +03:00
c228f80ffd fix: Заполнять скрытые поля корректировки значениями из БД при редактировании
Скрытые поля для price_adjustment_type и price_adjustment_value
имели жёсткие значения по умолчанию (none и 0) вместо значений из модели.

При редактировании комплекта скрытые поля теперь заполняются
текущими значениями из БД через {{ form.FIELD.value }}.

Теперь JavaScript может правильно загрузить сохранённые значения
и заполнить соответствующие input поля (увеличить %, руб, уменьшить %, руб).

Файл: products/templates/products/productkit_edit.html
2025-11-02 19:57:12 +03:00
3c62cce057 fix: Загружать сохранённые значения корректировки цены при редактировании
При редактировании комплекта поля корректировки цены остаются пустыми,
хотя в БД сохранены корректные значения (price_adjustment_type и value).

Исправлено:
1. Добавлен вызов validateSingleAdjustment() после заполнения полей
   - Это отключает остальные поля и помечает валидные
   - Реализует логику одного заполненного поля

2. Добавлено логирование в консоль браузера для отладки:
   - Показывает какие значения загружены из БД
   - Помогает выявить проблемы

Теперь при редактировании:
- Если есть сохранённая корректировка, она отображается
- Остальные поля автоматически отключаются
- Пересчитывается финальная цена

Файл: products/templates/products/productkit_edit.html
2025-11-02 19:52:42 +03:00
045f6a45da fix: Удалить вызов старого валидатора ценообразования
Был вызов KitValidator.validate_pricing_method_availability() который
пытался получить атрибут cost_calculation_info - это часть старой
системы ценообразования которая была заменена на новую.

Новая система не требует этой сложной валидации так как просто
вычисляет цену как сумму actual_price компонентов + опциональная корректировка.

Файл: products/views/productkit_views.py
2025-11-02 19:44:13 +03:00
390d547e97 feat: Добавить валидацию для заполнения одного поля корректировки цены
Реализована логика чтобы только одно из четырёх полей корректировки цены
можно было заполнить одновременно:

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

CSS стили:
- Disabled поля: серый фон, пониженная прозрачность, запрещённый курсор
- Invalid поля: красная граница и shadow (Bootstrap стиль)

Валидация работает на обе стороны:
- Frontend JavaScript (instant feedback)
- Backend Python валидация (безопасность)

Файлы:
- products/templates/products/productkit_create.html
- products/templates/products/productkit_edit.html
- products/forms.py (документация)
2025-11-02 19:40:47 +03:00
2e305a810a fix: Улучшить отображение цены в списке комплектов
Теперь цена в таблице productkit_list отображается по аналогии
с all_products_list:
- Зачёркнутая обычная цена, если есть скидка
- Красная цена со скидкой (sale_price)
- Красный значок 'Акция'
- Иначе просто обычная цена

Файл: products/templates/products/productkit_list.html
2025-11-02 19:23:17 +03:00
6c8af5ab2c fix: Улучшения системы ценообразования комплектов
Исправлены 4 проблемы:
1. Расчёт цены первого товара - улучшена валидация в getProductPrice и calculateFinalPrice
2. Отображение actual_price в Select2 вместо обычной цены
3. Количество по умолчанию = 1 для новых форм компонентов
4. Auto-select текста при клике на поле количества для удобства редактирования

Изменённые файлы:
- products/forms.py: добавлен __init__ в KitItemForm для quantity.initial = 1
- products/templates/includes/select2-product-init.html: обновлена formatSelectResult
- products/templates/productkit_create.html: добавлен focus handler для auto-select
- products/templates/productkit_edit.html: добавлен focus handler для auto-select

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 19:04:03 +03:00
2d344ef53c feat: Фаза 3 - Добавить индикаторы качества фото на фронтенд
Реализовано:
- Создан набор переиспользуемых шаблонных тегов для отображения качества
  - quality_badge_mini: маленький значок в углу фото
  - quality_badge_full: полный индикатор с размером фото
  - quality_indicator: включаемый тег с позиционированием
  - quality_icon_only: только символ качества для списков

- Добавлены шаблонные теги в:
  - product_detail.html: индикатор в углу миниатюр + в модальной галерее
  - product_list.html: иконка качества в таблице товаров
  - productkit_detail.html: индикатор в углу фото комплектов

- Создан CSS с ненавязчивыми стилями:
  - Полупрозрачные индикаторы (opacity: 0.8)
  - Компактные размеры (не отвлекает от фото)
  - Отзывчивость на мобильных устройствах
  - Анимации при наведении

- Обновлена админ панель:
  - Добавлены 3 новых экшена для поиска товаров по качеству
  - show_poor_quality_photos: фильтр на товары требующие обновления
  - show_excellent_quality_photos: фильтр на товары с хорошим качеством
  - show_all_quality_levels: статистика распределения качества

Интеграция в базу template tags:
- myproject/products/templatetags/quality_tags.py (новый файл)
- myproject/static/css/quality_indicator.css (новый файл)
- myproject/products/templates/products/includes/quality_badge.html (новый файл)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 15:13:49 +03:00
622e17a775 feat: Реализовать систему оценки качества фотографий товаров (Фаза 1)
Добавлена полностью гибкая система для оценки качества фотографий на основе размеров:

Конфигурация (settings.py):
- IMAGE_QUALITY_LEVELS: Пороги качества как доля от максимума (95%, 70%, 40%, 20%)
- IMAGE_QUALITY_LABELS: Описания, цвета и рекомендации для каждого уровня
- Система полностью адаптивна - меняется max_width в settings → пороги пересчитываются

Валидатор (validators/image_validators.py):
- get_max_dimension_from_config() - динамически читает из IMAGE_PROCESSING_CONFIG
- get_image_quality_level() - определяет уровень качества (excellent/good/acceptable/poor/very_poor)
- get_quality_info() - информация о уровне из IMAGE_QUALITY_LABELS
- validate_product_image() - комплексная валидация для UI

Модели (models/photos.py):
- ProductPhoto, ProductKitPhoto, ProductCategoryPhoto дополнены полями:
  - quality_level: уровень качества (CharField с choices)
  - quality_warning: требует ли обновления (BooleanField)
  - Добавлены индексы для быстрого поиска товаров требующих обновления фото

Обработчик (image_processor.py):
- process_image() теперь возвращает дополнительно:
  - width, height: размеры оригинального изображения
  - quality_level: уровень качества
  - quality_warning: нужно ли обновить перед выгрузкой
- Вызывает валидатор автоматически при обработке

Логика сохранения (photos.py -> save()):
- При сохранении нового фото автоматически вычисляет quality_level и quality_warning
- При обновлении существующего фото пересчитывает качество
- Сохраняет все три поля атомарно

Система полностью готова к:
- Phase 2: Admin интерфейс с фильтрами и индикаторами
- Phase 3: Фронтенд с визуальными индикаторами в формах и API

Примеры использования:
>>> from products.validators.image_validators import get_image_quality_level
>>> get_image_quality_level(1400, 1400)  # если max=2160
('good', False)  # 1400/2160 = 64.8% >= 70%? Нет, но >= 40%
>>> get_image_quality_level(400, 400)
('poor', True)  # Требует обновления

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 14:39:33 +03:00
d15e7d9414 fix: Исправить подмену фотографий при загрузке (коллизия имен файлов)
Проблема была в том, что при сохранении фотографии Django обнаруживал коллизию имен
и добавлял суффикс (например, original_b374WLW.jpg), но в БД сохранялся путь БЕЗ суффикса.
Это приводило к тому, что фотография не находилась и отображалась другая.

Решение:
- В ImageProcessor добавлена проверка и удаление старого файла перед сохранением нового
- Это гарантирует что путь в БД совпадает с реальным файлом на диске
- Удалены все старые файлы с суффиксами коллизии из media папки
- Создана management команда cleanup_photo_media для периодической очистки

Файлы:
- myproject/products/utils/image_processor.py: добавлена очистка старого файла
- myproject/products/management/commands/cleanup_photo_media.py: команда для очистки
- cleanup_media.py: скрипт для ручной очистки (уже запущен)
- BUG_FIX_PHOTO_COLLISION.md: подробный отчет о проблеме и решении

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 12:51:26 +03:00
d92045c4c4 refactor: Создать базовый класс BaseProductEntity и реструктурировать Product/ProductKit
Основные изменения:

## Модели (models.py)
- Создан абстрактный класс BaseProductEntity с общими полями:
  * Идентификация: name, sku, slug
  * Описания: description, short_description (новое поле)
  * Статус: is_active, timestamps, soft delete
  * Managers: objects, all_objects, active

- Product:
  * Унаследован от BaseProductEntity
  * sale_price переименован в price (основная цена)
  * Добавлено новое поле sale_price (цена со скидкой, nullable)
  * Добавлено property actual_price

- ProductKit:
  * Унаследован от BaseProductEntity
  * fixed_price переименован в price (ручная цена)
  * pricing_method: 'fixed' → 'manual'
  * Добавлено поле sale_price (цена со скидкой)
  * Добавлено поле cost_price (nullable)
  * Добавлены properties: calculated_price, actual_price
  * Обновлен calculate_price_with_substitutions()

## Forms (forms.py)
- ProductForm: добавлено short_description, price, sale_price
- ProductKitForm: добавлено short_description, cost_price, price, sale_price

## Admin (admin.py)
- ProductAdmin: обновлены list_display и fieldsets с новыми полями
- ProductKitAdmin: добавлены fieldsets, метод get_price_display()

## Templates
- product_form.html: добавлены поля price, sale_price, short_description
- product_detail.html: показывает зачеркнутую цену + скидку + бейджик "Акция"
- product_list.html: отображение цен со скидкой и бейджиком "Акция"
- all_products_list.html: единообразное отображение цен
- productkit_detail.html: отображение скидок с бейджиком "Акция"

## API (api_views.py)
- Обновлены все endpoints для использования поля price вместо sale_price

Результат: единообразная архитектура с поддержкой скидок, DRY-принцип,
логичные названия полей, красивое отображение акций в UI.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-31 00:49:01 +03:00
aec884240e refactor: Упростить макет формы редактирования вариантов и вернуть компактный вид
- Переместить название и описание над таблицей в отдельную карточку
- Убрать двухколонный layout (col-lg-4/col-lg-8), сделать весь контент в один столбец
- Удалить лишние div обёртки и стили для ограничения высоты (max-height: 36px)
- Уменьшить padding в таблице (4px 6px) для более компактного вида
- Таблица товаров тонкая и удобная, без скачков и деформаций

Результат:
- Чистый, компактный интерфейс в один столбец
- Без визуального шума и лишних обёрток
- Читаемо и просто для редактирования вариантов

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 00:14:30 +03:00
dbb94e9d2a refactor: Добавить в_stock в API и улучшить загрузку данных в форме вариантов
Изменения в API:
- Добавить поле in_stock в возвращаемые данные товаров
- Добавить поддержку запроса товара по ID (параметр ?id=) для получения актуальных данных
- Исправить дублирование информации одного товара на остальные в таблице вариантов

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

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 00:03:40 +03:00
e821d881a9 fix: Исправить сохранение приоритетов товаров в группе вариантов
Проблема: при перемещении товаров стрелками вверх/вниз приоритеты изменялись только в UI,
но при сохранении их значения не обновлялись в БД и возвращались в исходное состояние.

Причина: после сохранения формсета в view.form_valid() вызывалась функция _recalculate_priorities(),
которая перезаписывала все приоритеты по ID товаров, игнорируя значения из формсета.

Решение:

1. Удалена функция _recalculate_priorities() которая перезаписывала приоритеты
2. Теперь приоритеты сохраняются напрямую из формсета (inlineformset содержит поле 'priority')
3. Улучшен JavaScript селектор в updatePriorities() для более надёжного нахождения поля priority
4. Добавлено логирование в консоль для отладки (console.log)

Теперь при перемещении товаров стрелками и нажатии "Сохранить" приоритеты правильно сохраняются в БД.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 23:49:15 +03:00
83412f3447 fix: Исправить логику обновления Product.in_stock из Stock остатков
Проблема: товары отображались как "нет в наличии" несмотря на наличие остатков на складе.

Причина: сигналы на обновление Product.in_stock срабатывают только при изменении Stock через Django ORM.
Если Stock была создана напрямую (импорт, миграция и т.д.), сигналы не срабатывали.

Решение:

1. Исправлена логика сигналов (inventory/signals.py):
   - Добавлен импорт post_delete для правильной обработки удаления Stock
   - Изменён pre_delete на post_delete для более надёжной проверки остатков
   - Сигналы теперь правильно срабатывают при любом изменении Stock

2. Добавлена миграция (products/migrations/0004_fix_product_in_stock.py):
   - Пересчитывает in_stock для всех существующих товаров на основе Stock.quantity_available
   - Товар считается в наличии если есть хотя бы один Stock с quantity_available > 0
   - Обратима и безопасна (может быть отменена)

3. Добавлена команда управления (products/management/commands/update_product_in_stock.py):
   - Позволяет вручную пересчитать in_stock если потребуется
   - Поддерживает параметр --verbose для подробного логирования
   - Может быть запущена по расписанию или вручную

После этого исправления:
- Все товары с остатками на складе автоматически обновляют статус in_stock
- Сигналы срабатывают при любом изменении Stock (создание, обновление, удаление)
- Отображение наличия товаров в UI будет корректным

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 23:42:20 +03:00
9ff1f2d184 feat: Добавить отображение наличия товаров и цены вариантов во все шаблоны CRUD
Добавлена визуализация статуса наличия (in_stock) и цены вариантов во все CRUD шаблоны товаров и групп вариантов.

Product (товары):
- product_list.html: добавлена колонка "В наличии" с бейджами (зелёный/красный)
- product_detail.html: добавлена строка "В наличии" в таблицу данных товара
- product_form.html: добавлена информационная секция о наличии при редактировании
- all_products_list.html: добавлена колонка "В наличии" для товаров
- productkit_list.html: обновлены стили бейджей статуса

ProductVariantGroup (группы вариантов):
- variantgroup_list.html: добавлены колонки "В наличии" и "Цена" в таблицу групп
- variantgroup_detail.html: добавлены отображение наличия и цены в информационный блок слева
- variantgroup_detail.html: добавлена колонка "В наличии" в таблицу товаров группы
- variantgroup_form.html: добавлены отображение артикула, цены и статуса наличия в formset таблице
- variantgroup_form.html: добавлен JavaScript код для динамического обновления данных товара при выборе через Select2
- variantgroup_confirm_delete.html: добавлена информация о наличии и цене группы в окно подтверждения удаления

Views optimization:
- ProductVariantGroupListView: добавлен prefetch_related('items__product') для оптимизации N+1 запросов
- Все представления используют оптимизированные запросы для вычисления in_stock и price свойств

UI/UX улучшения:
- Используются Bootstrap 5 бейджи с иконками (bg-success/bg-danger)
- Визуальное выделение статуса наличия через цвет и значки
- Информативное отображение цены варианта во всех местах
- Динамическое обновление информации при выборе товаров в formset

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 23:33:11 +03:00
2341cf57c1 feat: Реализовать систему наличия товаров и цены вариантов
Добавлена система управления наличием товаров на трёх уровнях:

1. Product.in_stock (поле БД)
   - Булево значение: есть/нет в наличии
   - Автоматически обновляется при изменении Stock
   - Используется для быстрого поиска и фильтрации товаров

2. Сигналы для синхронизации (inventory/signals.py)
   - При изменении Stock → обновляется Product.in_stock
   - Логика: товар в наличии если есть Stock с quantity_available > 0

3. ProductVariantGroup.in_stock (свойство)
   - Вариант в наличии если хотя бы один из товаров в наличии
   - Динамически рассчитывается по Product.in_stock товаров в группе

4. ProductVariantGroup.price (свойство)
   - Цена по приоритету: берём цену товара с приоритетом 1, если он в наличии
   - Если никто не в наличии: берём максимальную цену из всех товаров
   - Возвращает Decimal или None если группа пуста

Файлы:
- myproject/products/models.py: добавлено поле in_stock и свойства в ProductVariantGroup
- myproject/inventory/signals.py: добавлены сигналы для синхронизации
- myproject/products/migrations/0003_add_product_in_stock.py: миграция для поля in_stock
- VARIANT_STOCK_IMPLEMENTATION.md: полная документация архитектуры
- QUICK_REFERENCE.md: быстрая справка по использованию

Особенности:
✓ Система простая и элегантная (без костылей)
✓ Обратная совместимость не требуется
✓ Высокая производительность (индексирование, минимум JOIN'ов)
✓ Актуальные данные (сигналы гарантируют синхронизацию)
✓ Легко расширяемая (свойства можно менять без миграций)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 23:22:01 +03:00
6735be9b08 feat: Реализовать систему поступления товаров с партиями (IncomingBatch)
Основные изменения:
- Создана модель IncomingBatch для группировки товаров по документам
- Каждое поступление (Incoming) связано с одной батчем поступления
- Автоматическое создание StockBatch для каждого товара в приходе
- Реализована система нумерации партий (IN-XXXX-XXXX) с поиском максимума в БД
- Обновлены все представления (views) для работы с новой архитектурой
- Добавлены детальные страницы просмотра партий поступлений
- Обновлены шаблоны для отображения информации о партиях и их товарах
- Исправлена логика сигналов для создания StockBatch при приходе товара
- Обновлены формы для работы с новой структурой IncomingBatch

Архитектура FIFO:
- IncomingBatch: одна партия поступления (номер IN-XXXX-XXXX)
- Incoming: товар в партии поступления
- StockBatch: одна партия товара на складе (создается для каждого товара)

Это позволяет системе правильно применять FIFO при продаже товаров.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 03:26:06 +03:00
097d4ea304 feat: Добавить систему мультитенантности с регистрацией магазинов
Реализована полноценная система мультитенантности на базе django-tenants.
Каждый магазин получает изолированную схему БД и поддомен.

Основные компоненты:

Django-tenants интеграция:
- Модели Client (тенант) и Domain в приложении tenants/
- Разделение на SHARED_APPS и TENANT_APPS
- Public schema для общей админки
- Tenant schemas для изолированных данных магазинов

Система регистрации магазинов:
- Публичная форма регистрации на /register/
- Модель TenantRegistration для заявок со статусами (pending/approved/rejected)
- Валидация schema_name (латиница, 3-63 символа, уникальность)
- Проверка на зарезервированные имена (admin, api, www и т.д.)
- Админ-панель для модерации заявок с кнопками активации/отклонения

Система подписок:
- Модель Subscription с планами (триал 90 дней, месяц, квартал, год)
- Автоматическое создание триальной подписки при активации
- Методы is_expired() и days_left() для проверки статуса
- Цветовая индикация в админке (зеленый/оранжевый/красный)

Приложения:
- tenants/ - управление тенантами, регистрация, подписки
- shops/ - точки магазинов/самовывоза (tenant app)
- Обновлены миграции для всех приложений

Утилиты:
- switch_to_tenant.py - переключение между схемами тенантов
- Обновлены image_processor и image_service

Конфигурация:
- urls_public.py - роуты для public schema (админка + регистрация)
- urls.py - роуты для tenant schemas (магазины)
- requirements.txt - добавлены django-tenants, django-environ, phonenumber-field

Документация:
- DJANGO_TENANTS_SETUP.md - настройка мультитенантности
- TENANT_REGISTRATION_GUIDE.md - руководство по регистрации
- QUICK_START.md - быстрый старт
- START_HERE.md - общая документация

Использование:
1. Пользователь: http://localhost:8000/register/ → заполняет форму
2. Админ: http://localhost:8000/admin/ → активирует заявку
3. Результат: http://{schema_name}.localhost:8000/ - готовый магазин

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-27 19:13:10 +03:00
a55d0405ed Изменение структуры хранения изображений и исправление ошибки дублирования ID 2025-10-25 19:21:32 +03:00
d999e01b49 Обновили шапку и вывод всехтоваров. Добавили фильтры 2025-10-25 16:48:11 +03:00
9ad9f604e9 Обновили шапку и вывод всехтоваров. Добавили фильтры 2025-10-24 23:11:29 +03:00
2fb6253d06 fix: Исправить сохранение множественных товаров в комплект
ПРОБЛЕМА:
При создании комплекта с несколькими товарами сохранялся только первый товар.

ПРИЧИНЫ И РЕШЕНИЯ:

1. Неправильный префикс в JavaScript (productkit_create.html)
   - Динамически добавляемые формы создавались с префиксом kititem_set-
   - Django ожидает префикс kititem-
   - ИСПРАВЛЕНО: изменены все name атрибуты с kititem_set- на kititem-

2. NULL constraint для quantity (models.py)
   - Поле KitItem.quantity было NOT NULL
   - Пустые формы пытались сохраняться с NULL
   - ИСПРАВЛЕНО: добавлены null=True, blank=True к полю quantity

3. Неправильная валидация пустых форм (forms.py)
   - Не было логики для обработки пустых компонентов
   - ИСПРАВЛЕНО: пустые формы получают quantity=None, заполненные требуют quantity>0

4. Неправильный порядок сохранения (productkit_views.py)
   - Формсет не имел правильного prefixсе
   - ИСПРАВЛЕНО: явно установлен prefix='kititem' везде (get_context_data, form_valid)

 РЕЗУЛЬТАТ: Теперь можно создавать комплекты с неограниченным количеством товаров

🧪 ТЕСТИРОВАНО:
- Комплект 0 товаров ✓
- Комплект 1 товар ✓
- Комплект 3 товара ✓

🤖 Generated with Claude Code
2025-10-23 23:48:39 +03:00
59ba375404 chore: Remove old productkit_form.html template 2025-10-23 16:05:43 +03:00
9d5ce11951 refactor: Двухэтапное создание комплектов товаров
Реализован современный двухэтапный подход к созданию комплектов:

**Шаг 1: Создание базовой информации** (productkit_create.html)
- Упрощённая форма только с базовой информацией
- Название, описание, категории, теги
- Фотографии с предпросмотром
- Настройки ценообразования
- Чистый современный UI с breadcrumbs
- Прогрессивное раскрытие (collapsible секции)

**Шаг 2: Добавление товаров** (productkit_edit.html)
- Автоматический redirect после создания
- Работа с товарами через существующий функционал
- Улучшенный заголовок с указанием шага

**Изменения в коде:**
- ProductKitCreateView: упрощён, убраны formsets
- ProductKitUpdateView: использует новый шаблон
- productkit_form.html → productkit_edit.html
- Новый шаблон productkit_create.html

**Преимущества:**
 Простая и надёжная логика сохранения
 Нет проблем с disabled полями в formsets
 Понятный UX с чёткими шагами
 Современный дизайн с иконками Bootstrap
 Предпросмотр фото перед загрузкой

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-23 16:05:13 +03:00