refactor(db): консолидация миграций и рефакторинг кода

Объединены изменения из промежуточных миграций в начальные миграции для упрощения истории базы данных.
Удалены миграции: accounts/0002, discounts/0002, orders/0003-0004, products/0002-0005, user_roles/0002, system_settings/0001-0002, integrations/0001-0002.
Добавлена автоматическая creation пользователя при установке пароля.
Обновлен UI страницы установки пароля с кастомным стилем.
Добавлен conditional rendering для кнопки синхронизации Recommerce.
Исправлены редиректы с 'index' на '/' в accounts views.
Добавлена проверка request.tenant в navbar и authenticate метод в auth backend.
This commit is contained in:
2026-01-14 16:30:28 +03:00
parent e7672588c6
commit caeb3f80bd
31 changed files with 238 additions and 558 deletions

View File

@@ -175,7 +175,7 @@ class ProductDetailView(LoginRequiredMixin, ManagerOwnerRequiredMixin, DetailVie
product_photos.sort(key=lambda x: (x.order, x.created_at))
context['product_photos'] = product_photos
context['photos_count'] = len(product_photos)
# Кешируем cost_price_details, чтобы не делать множественные запросы к БД
from ..services.cost_calculator import ProductCostCalculator
context['cost_price_details'] = ProductCostCalculator.get_cost_details(self.object)
@@ -277,7 +277,7 @@ class CombinedProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Lis
def get_queryset(self):
# Получаем фильтр по типу
type_filter = self.request.GET.get('type', 'all')
# Получаем товары и комплекты (только постоянные комплекты)
# Аннотируем товары данными об остатках из агрегированной таблицы Stock
total_available = Coalesce(Sum('stocks__quantity_available'), Value(0), output_field=DecimalField())
@@ -331,13 +331,13 @@ class CombinedProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Lis
elif is_active_filter == '0':
products = products.filter(status__in=['archived', 'discontinued'])
kits = kits.filter(status__in=['archived', 'discontinued'])
# Фильтрация по наличию (только для товаров)
if in_stock_filter == '1':
products = products.filter(in_stock=True)
elif in_stock_filter == '0':
products = products.filter(in_stock=False)
# Фильтрация по тегам
if tags:
products = products.filter(tags__id__in=tags).distinct()
@@ -382,12 +382,12 @@ class CombinedProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Lis
# Применяем фильтр по типу
products_list = []
kits_list = []
if type_filter in ['all', 'products']:
products_list = list(products.order_by('-created_at'))
for p in products_list:
p.item_type = 'product'
if type_filter in ['all', 'kits']:
kits_list = list(kits.order_by('-created_at'))
for k in kits_list:
@@ -411,6 +411,11 @@ class CombinedProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Lis
from ..models.base import BaseProductEntity
item_statuses = BaseProductEntity.STATUS_CHOICES
# Получаем состояние интеграции Recommerce
from integrations.models import RecommerceIntegration
recommerce_integration = RecommerceIntegration.objects.first()
context['recommerce_integration_enabled'] = recommerce_integration.is_active if recommerce_integration else False
# Данные для фильтров
context['filters'] = {
'categories': ProductCategory.objects.filter(is_active=True),
@@ -431,7 +436,7 @@ class CombinedProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Lis
'has_discount': self.request.GET.get('has_discount', ''),
}
}
context['item_statuses'] = item_statuses
# Кнопки действий