- Implement `check_released_reservations_available` function to verify if items from released reservations are still available for re-sale when attempting to change a returned order's status
- Update `create_sale_on_order_completion` signal to use this check, allowing transitions to positive statuses only if items are available, otherwise blocking with ValidationError
- Wrap Order.save() in transaction.atomic() to ensure ValidationError in signals rolls back the save operation
- Add comprehensive tests for scenarios where items are available or used in other orders
- Update date carousel in order to always center on today's date and remove unnecessary saving logic
- Add test flag to Django Debug Toolbar settings
Closes#123 (assuming related issue)
- Add script to set correct permissions on static files after collectstatic
- Introduce collectstatic command in entrypoint with permission fixing
- Add WhiteNoise middleware for efficient static file serving without DB access
- Configure WhiteNoise static files storage backend in settings
- Set STATIC_ROOT path properly for Docker container environment
- Add fallback static files serving in Django urls for production without nginx
- Enhance inventory_detail.html scripts to log errors if JS files or components fail to load
- Add whitenoise package to requirements for static file serving support
- Fix MEDIA_ROOT path to match Docker volume mount (/app/myproject/media)
- Update docker-compose.yml volume mounts to match MEDIA_ROOT
- Add setup_directories() function in entrypoint.sh to create media directories with proper permissions
- Add logging to TenantAwareFileSystemStorage for debugging
- Fix is_returned flag logic improvements (from previous work)
- Изменён TIME_ZONE с Europe/Moscow на Europe/Minsk в settings.py
- Исправлено создание заказов в POS: теперь используется timezone.localtime() для корректной конвертации UTC → Minsk
- delivery_date и delivery_time_start/end теперь сохраняются в минском времени, а не UTC
- Исправлена разница в 3 часа между временем создания заказа и фактическим временем
- Удалено устаревшее поле payment_method из showcase_manager.py (поле было удалено из модели Order)
Теперь все временные метки заказов соответствуют реальному минскому времени
- Добавлена специальная обработка витринных комплектов в сигнале update_reservation_on_item_change:
* При создании OrderItem с витринным комплектом привязываются существующие витринные резервы компонентов
* Не создаются новые резервы на уровне комплекта
- Исправлена логика создания Sale для комплектов в сигнале create_sale_on_order_completion:
* Для комплектов (витринных и обычных) создаются Sale для каждого компонента через резервы
* Используется FIFO-списание для компонентов
* Предотвращена ошибка передачи ProductKit в поле Reservation.product
Fixes: Cannot assign ProductKit to Reservation.product field
Fixes: Не удалось создать Sale для заказа с витринным комплектом
- Добавлена поддержка docker-compose для развертывания
- STATIC_ROOT автоматически переключается в prod (/Volume1/DockerAppsData/npm/data/static/)
- Добавлены ALLOWED_HOSTS и CSRF_TRUSTED_ORIGINS из env переменных
- Улучшена обработка .env файла (проверка существования)
- Добавлен gunicorn в requirements.txt
- Добавлены .dockerignore, Dockerfile, docker-compose.yml
- Добавлены example файлы для .env.docker и entrypoint.sh
- Обновлен .gitignore для исключения файлов с секретами
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Удалены из git:
- Скрипты активации и диагностики тенантов
- Тестовые файлы (test_*.py, test_*.txt)
- SQL скрипты для отладки
- Backup файлы (*.backup, *.old)
- Дубликат .gitignore из myproject/
Файлы остались на диске, но теперь игнорируются git.
В репозитории остались только:
- myproject/ (основной код проекта)
- requirements.txt
- .gitignore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Исправлена критическая уязвимость безопасности, которая потенциально позволяла
владельцам тенантов получить доступ к админ-панели Django.
Изменения:
- Добавлены явные setdefault для is_staff=False и is_superuser=False в CustomUserManager.create_user()
- Добавлены явные флаги безопасности при создании владельца тенанта
- Добавлены явные флаги безопасности при создании пользователей через систему ролей
- Создан TenantAdminAccessMiddleware для защиты /admin/ на уровне middleware
- Создана миграция данных для исправления флагов у существующих пользователей
Реализована трёхуровневая защита (Defense-in-Depth):
1. Уровень модели: явные дефолты в create_user()
2. Уровень views: явные флаги при создании
3. Уровень middleware: runtime блокировка доступа
Файлы:
- accounts/models.py: явные флаги в create_user()
- tenants/admin.py: явные флаги при создании владельца
- user_roles/views.py: явные флаги при создании через роли
- myproject/admin_access_middleware.py: новый middleware
- myproject/settings.py: регистрация middleware
- accounts/migrations/0002_fix_owner_staff_flags.py: миграция данных
ВАЖНО: После применения этого коммита необходимо выполнить:
1. python manage.py migrate accounts
2. python manage.py migrate_schemas
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added get_user_model import in accounts/views.py
- Fixed User variable scope in password_setup_confirm view
- Added accounts URLs to urls_public.py for password setup on main domain
- Password setup link now accessible from public schema
Technical details:
- get_user_model() needed to be imported from django.contrib.auth
- User model reference moved outside try block to fix UnboundLocalError
- accounts.urls included in public URLconf for /accounts/setup-password/ route
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added role management views (list, create, edit, delete)
- Created user_roles URL routing
- Added role management templates with Bootstrap styling
- Updated navbar with Roles link for owners and superusers
- Enhanced decorators and mixins with superuser bypass
- Added assign_owner_role.py utility script
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Добавлена система ролей пользователей для управления доступом в multi-tenant приложении.
Новые роли:
- Владелец (Owner): полный доступ, управление пользователями
- Менеджер (Manager): управление заказами, клиентами, товарами, складом
- Флорист (Florist): работа с заказами и складскими операциями
- Курьер (Courier): роль создана, права будут определены позже
Архитектура:
- Роли автоматически изолируются по тенантам через django-tenants (TENANT_APPS)
- Не требуется FK на Client/Tenant - изоляция через PostgreSQL schemas
- Роли автоматически создаются при создании нового тенанта
Компоненты:
- user_roles/models.py: модели Role и UserRole
- user_roles/services.py: RoleService для управления ролями
- user_roles/decorators.py: @role_required, @owner_required
- user_roles/mixins.py: RoleBasedAdminMixin, OwnerOnlyAdminMixin
- user_roles/admin.py: админка для управления ролями
- user_roles/management/commands/init_roles.py: команда для инициализации
Изменения:
- accounts/models.py: добавлены helper методы (is_owner, has_role, etc)
- settings.py: добавлен user_roles в TENANT_APPS
- tenants/admin.py: автосоздание ролей при создании тенанта
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Resolves critical bug where photos of products with the same ID in different
tenants were overwriting each other. Implemented complete isolation of media
files between tenants using custom Django storage backend.
## Changes
### New Files
- products/utils/storage.py: TenantAwareFileSystemStorage backend
* Automatically adds tenant_id to file paths on disk
* Prevents cross-tenant file access with security checks
* Stores clean paths in DB for portability
- products/tests/test_multi_tenant_photos.py: Comprehensive tests
* 5 tests covering isolation, security, and configuration
* All tests passing ✅
- MULTITENANT_PHOTO_FIX.md: Complete documentation
### Modified Files
- settings.py: Configured DEFAULT_FILE_STORAGE to use TenantAwareFileSystemStorage
- products/models/photos.py:
* Converted upload_to from strings to callable functions
* Updated ProductPhoto, ProductKitPhoto, ProductCategoryPhoto
* Added tenant isolation documentation
- products/tasks.py: Added documentation about file structure
- products/utils/image_processor.py: Added documentation
- products/utils/image_service.py: Added documentation
## Architecture
**On disk:** media/tenants/{tenant_id}/products/{entity_id}/{photo_id}/{size}.ext
**In DB:** products/{entity_id}/{photo_id}/{size}.ext
Tenant ID is automatically added/removed during file operations.
## Security
- Storage rejects cross-tenant file access
- Proper tenant context validation
- Integration with django-tenants schema system
## Testing
- All 5 multi-tenant photo tests pass
- Verified photo paths are isolated per tenant
- Verified storage rejects cross-tenant access
- Verified configuration is correct
## Future-proof
- Ready for S3 migration (just change storage backend)
- No breaking changes to existing code
- Clean separation of concerns
Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented Redis caching with 2-hour TTL for POS session data:
Backend changes:
- Added Redis cache configuration in settings.py
- Created save_cart() endpoint to persist cart state
- Added cart and customer loading from Redis in pos_terminal()
- Validates cart items (products/kits) still exist in DB
- Added REDIS_HOST, REDIS_PORT, REDIS_DB to .env
Frontend changes:
- Added saveCartToRedis() with 500ms debounce
- Cart auto-saves on add/remove/quantity change
- Added cart initialization from Redis on page load
- Enhanced customer button with two-line display and reset button
- Red X button appears only for non-system customers
Features:
- Cart persists across page reloads (2 hour TTL)
- Customer selection persists (2 hour TTL)
- Independent cart per user+warehouse combination
- Automatic cleanup of deleted items
- Debounced saves to reduce server load
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
При асинхронной обработке фото нужно сначала сохранить файл в БД,
потом запустить Celery task. Иначе task не найдет файл.
Изменения:
- BasePhoto.save() теперь сохраняет файл перед запуском task
- Исправлена проблема 'Photo has no image file' в Celery worker
🤖 Generated with Claude Code
Упрощена логика системы путём замены отдельной сущности "Магазин"
на универсальную сущность "Склад", которая может использоваться
как точка самовывоза.
Изменения:
- Расширена модель 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>
- Упрощена модель Shop: только name обязательное поле
- Удалены поля: district, режим работы, координаты, инструкции
- Description перенесено после name
- Все поля кроме name теперь опциональные
- Создан полный CRUD для магазинов:
* ShopListView - список магазинов с пагинацией
* ShopCreateView - создание нового магазина
* ShopUpdateView - редактирование магазина
* ShopDeleteView - удаление с подтверждением
- Создана форма ShopForm с Bootstrap стилями
- Поле "Название магазина" помечено как обязательное (*)
- Настроена обработка PhoneNumberField
- Созданы шаблоны:
* shop_list.html - таблица со списком магазинов
* shop_form.html - форма создания/редактирования
* shop_confirm_delete.html - подтверждение удаления
- Настроены URLs для приложения shops
- Добавлена ссылка "Магазины" в главную навигацию
- Обновлена админ-панель shops
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Основные изменения:
- Установлен и настроен django-filter==24.3
- Создан OrderFilter с фильтрами по дате доставки, статусу, типу, оплате и поиску
- Реализован переиспользуемый компонент календарного фильтра date_range_filter.html
- Добавлены быстрые кнопки выбора дат (Сегодня, Завтра, Неделя)
- Создан templatetag param_replace для сохранения фильтров при пагинации
- Обновлен order_list view для использования django-filter
- Полностью переработан шаблон order_list.html с интеграцией фильтров
- Добавлены стили (date_filter.css) и логика (date_filter.js) для календаря
Структура новых файлов:
- orders/filters.py - FilterSet для заказов
- orders/templatetags/filter_tags.py - кастомные теги для фильтров
- orders/templates/orders/components/date_range_filter.html - компонент календаря
- orders/static/orders/css/date_filter.css - стили
- orders/static/orders/js/date_filter.js - JavaScript логика
- requirements.txt - зависимости проекта
Преимущества:
- Чистая архитектура фильтрации
- Автоматическое сохранение параметров при навигации
- Переиспользуемый календарный компонент
- Улучшенный UX с быстрыми фильтрами
- Готовность к масштабированию на другие модели
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Заказы:
- Добавлены миграции для исторических записей с полями оплаты и получателя
- Расширен 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>
Добавлена полностью гибкая система для оценки качества фотографий на основе размеров:
Конфигурация (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>
Основные изменения:
- Создана модель 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>
Реализована полноценная система мультитенантности на базе 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>
Реализована система автоматического создания суперпользователей при активации
новых тенантов (магазинов). Credentials читаются из .env файла.
Изменения:
- Подключен django-environ для управления переменными окружения
- Обновлен settings.py: SECRET_KEY, DEBUG, DATABASE теперь из .env
- Добавлены настройки TENANT_ADMIN_EMAIL, TENANT_ADMIN_PASSWORD, TENANT_ADMIN_NAME
- Обновлен tenants/admin.py: автоматическое создание superuser при активации
- Создан activate_tenant.py: универсальный скрипт активации заявок
- Обновлен activate_mixflowers.py: добавлено создание superuser
- Создан .gitignore для защиты секретов
- Добавлена документация TENANT_ADMIN_GUIDE.md
Использование:
1. Через админку: Заявки → Активировать (автоматически создаст superuser)
2. Через скрипт: python activate_tenant.py <schema_name>
Доступ к админке тенанта:
- URL: http://{schema_name}.localhost:8000/admin/
- Email: admin@localhost (из .env)
- Password: 1234 (из .env)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Refactored image processing system to use centralized configuration in settings.IMAGE_PROCESSING_CONFIG instead of hardcoded values.
Changes:
- Added IMAGE_PROCESSING_CONFIG to settings with configurable sizes, formats, and quality
- Rewrote ImageProcessor to use dynamic configuration from settings
- Added support for multiple image formats (JPEG, WebP, PNG)
- Updated _save_image_version() to handle different formats and quality levels
- Added original image scaling (max 2160×2160) and square aspect ratio
- Updated ImageService to work with different file extensions (.jpg, .webp, .png)
- All parameters now easily configurable without code changes
Configuration:
- Original: JPEG, quality 100, max 2160×2160 (always square)
- Large: WebP, quality 90, 1200×1200
- Medium: WebP, quality 85, 600×600
- Thumbnail: WebP, quality 80, 200×200
Benefits:
- Flexible and maintainable configuration
- Smaller file sizes (WebP for resized images)
- Maximum quality for originals (JPEG 100)
- Square aspect ratio for better consistency
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>