- Добавить name="submit" к кнопке формы - Запретить PlatformAdmin доступ к CRUD операций UnitOfMeasure - Исправить запрос sales_units_using через ProductSalesUnit.objects.filter Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
285 lines
9.9 KiB
Python
285 lines
9.9 KiB
Python
"""
|
||
Views для управления единицами измерения (Unit of Measure)
|
||
"""
|
||
from django.contrib.auth.decorators import login_required
|
||
from django.contrib import messages
|
||
from django.shortcuts import render, redirect, get_object_or_404
|
||
from django.db.models import Q, Count
|
||
from django.core.paginator import Paginator
|
||
from django.urls import reverse
|
||
|
||
from products.models import UnitOfMeasure, ProductSalesUnit
|
||
from products.forms import ProductSalesUnitForm, UnitOfMeasureForm
|
||
|
||
|
||
@login_required
|
||
def unit_of_measure_list(request):
|
||
"""
|
||
Список всех единиц измерения с возможностью фильтрации и поиска
|
||
"""
|
||
# Получаем параметры фильтрации
|
||
search_query = request.GET.get('q', '').strip()
|
||
is_active_filter = request.GET.get('is_active', '')
|
||
|
||
# Базовый queryset
|
||
units = UnitOfMeasure.objects.all()
|
||
|
||
# Аннотируем количество использований
|
||
units = units.annotate(
|
||
products_count=Count('products')
|
||
)
|
||
|
||
# Применяем фильтры
|
||
if search_query:
|
||
units = units.filter(
|
||
Q(code__icontains=search_query) |
|
||
Q(name__icontains=search_query) |
|
||
Q(short_name__icontains=search_query)
|
||
)
|
||
|
||
if is_active_filter:
|
||
units = units.filter(is_active=(is_active_filter == 'true'))
|
||
|
||
# Сортировка
|
||
units = units.order_by('position', 'code')
|
||
|
||
# Пагинация
|
||
paginator = Paginator(units, 50)
|
||
page_number = request.GET.get('page')
|
||
page_obj = paginator.get_page(page_number)
|
||
|
||
context = {
|
||
'page_obj': page_obj,
|
||
'search_query': search_query,
|
||
'is_active_filter': is_active_filter,
|
||
'total_units': units.count(),
|
||
}
|
||
|
||
return render(request, 'products/uom/unit_list.html', context)
|
||
|
||
|
||
@login_required
|
||
def unit_of_measure_create(request):
|
||
"""
|
||
Создание новой единицы измерения
|
||
"""
|
||
# Проверка: PlatformAdmin не имеет доступа к бизнес-данным тенантов
|
||
if request.user.__class__.__name__ == 'PlatformAdmin':
|
||
messages.error(request, 'У вас недостаточно прав для выполнения этого действия')
|
||
return redirect('products:unit-list')
|
||
|
||
if request.method == 'POST':
|
||
form = UnitOfMeasureForm(request.POST)
|
||
if form.is_valid():
|
||
unit = form.save()
|
||
messages.success(request, f'Единица измерения "{unit.name}" успешно создана!')
|
||
return redirect('products:unit-list')
|
||
else:
|
||
form = UnitOfMeasureForm()
|
||
|
||
context = {
|
||
'form': form,
|
||
'title': 'Создание единицы измерения',
|
||
'submit_text': 'Создать'
|
||
}
|
||
return render(request, 'products/uom/unit_form.html', context)
|
||
|
||
|
||
@login_required
|
||
def unit_of_measure_update(request, pk):
|
||
"""
|
||
Редактирование единицы измерения
|
||
"""
|
||
# Проверка: PlatformAdmin не имеет доступа к бизнес-данным тенантов
|
||
if request.user.__class__.__name__ == 'PlatformAdmin':
|
||
messages.error(request, 'У вас недостаточно прав для выполнения этого действия')
|
||
return redirect('products:unit-list')
|
||
|
||
unit = get_object_or_404(UnitOfMeasure, pk=pk)
|
||
|
||
if request.method == 'POST':
|
||
form = UnitOfMeasureForm(request.POST, instance=unit)
|
||
if form.is_valid():
|
||
unit = form.save()
|
||
messages.success(request, f'Единица измерения "{unit.name}" успешно обновлена!')
|
||
return redirect('products:unit-list')
|
||
else:
|
||
form = UnitOfMeasureForm(instance=unit)
|
||
|
||
context = {
|
||
'form': form,
|
||
'unit': unit,
|
||
'title': f'Редактирование: {unit.name}',
|
||
'submit_text': 'Сохранить'
|
||
}
|
||
return render(request, 'products/uom/unit_form.html', context)
|
||
|
||
|
||
@login_required
|
||
def unit_of_measure_delete(request, pk):
|
||
"""
|
||
Удаление единицы измерения
|
||
"""
|
||
# Проверка: PlatformAdmin не имеет доступа к бизнес-данным тенантов
|
||
if request.user.__class__.__name__ == 'PlatformAdmin':
|
||
messages.error(request, 'У вас недостаточно прав для выполнения этого действия')
|
||
return redirect('products:unit-list')
|
||
|
||
unit = get_object_or_404(UnitOfMeasure, pk=pk)
|
||
|
||
# Проверяем использование
|
||
products_using = unit.products.count()
|
||
sales_units_using = ProductSalesUnit.objects.filter(product__base_unit=unit).count()
|
||
|
||
can_delete = products_using == 0 and sales_units_using == 0
|
||
|
||
if request.method == 'POST':
|
||
if can_delete:
|
||
name = unit.name
|
||
unit.delete()
|
||
messages.success(request, f'Единица измерения "{name}" успешно удалена!')
|
||
return redirect('products:unit-list')
|
||
else:
|
||
messages.error(
|
||
request,
|
||
f'Невозможно удалить единицу измерения "{unit.name}". '
|
||
f'Она используется в {products_using} товарах и {sales_units_using} единицах продажи.'
|
||
)
|
||
return redirect('products:unit-list')
|
||
|
||
context = {
|
||
'unit': unit,
|
||
'can_delete': can_delete,
|
||
'products_using': products_using,
|
||
'sales_units_using': sales_units_using,
|
||
}
|
||
return render(request, 'products/uom/unit_delete.html', context)
|
||
|
||
|
||
@login_required
|
||
def product_sales_unit_list(request):
|
||
"""
|
||
Список всех единиц продажи товаров с возможностью фильтрации
|
||
"""
|
||
# Получаем параметры фильтрации
|
||
search_query = request.GET.get('q', '').strip()
|
||
is_active_filter = request.GET.get('is_active', '')
|
||
is_default_filter = request.GET.get('is_default', '')
|
||
|
||
# Базовый queryset
|
||
sales_units = ProductSalesUnit.objects.select_related('product').all()
|
||
|
||
# Применяем фильтры
|
||
if search_query:
|
||
sales_units = sales_units.filter(
|
||
Q(product__name__icontains=search_query) |
|
||
Q(product__sku__icontains=search_query) |
|
||
Q(name__icontains=search_query)
|
||
)
|
||
|
||
if is_active_filter:
|
||
sales_units = sales_units.filter(is_active=(is_active_filter == 'true'))
|
||
|
||
if is_default_filter:
|
||
sales_units = sales_units.filter(is_default=(is_default_filter == 'true'))
|
||
|
||
# Сортировка
|
||
sales_units = sales_units.order_by('product__name', 'position')
|
||
|
||
# Пагинация
|
||
paginator = Paginator(sales_units, 50)
|
||
page_number = request.GET.get('page')
|
||
page_obj = paginator.get_page(page_number)
|
||
|
||
context = {
|
||
'page_obj': page_obj,
|
||
'search_query': search_query,
|
||
'is_active_filter': is_active_filter,
|
||
'is_default_filter': is_default_filter,
|
||
'total_sales_units': sales_units.count(),
|
||
}
|
||
|
||
return render(request, 'products/uom/sales_unit_list.html', context)
|
||
|
||
|
||
@login_required
|
||
def product_sales_unit_create(request):
|
||
"""
|
||
Создание новой единицы продажи
|
||
"""
|
||
if request.method == 'POST':
|
||
form = ProductSalesUnitForm(request.POST)
|
||
if form.is_valid():
|
||
sales_unit = form.save()
|
||
messages.success(
|
||
request,
|
||
f'Единица продажи "{sales_unit.name}" для товара "{sales_unit.product.name}" успешно создана!'
|
||
)
|
||
return redirect('products:sales-unit-list')
|
||
else:
|
||
# Предзаполнение товара если передан в параметрах
|
||
initial = {}
|
||
product_id = request.GET.get('product')
|
||
if product_id:
|
||
initial['product'] = product_id
|
||
|
||
form = ProductSalesUnitForm(initial=initial)
|
||
|
||
context = {
|
||
'form': form,
|
||
'title': 'Создание единицы продажи',
|
||
'submit_text': 'Создать'
|
||
}
|
||
return render(request, 'products/uom/sales_unit_form.html', context)
|
||
|
||
|
||
@login_required
|
||
def product_sales_unit_update(request, pk):
|
||
"""
|
||
Редактирование единицы продажи
|
||
"""
|
||
sales_unit = get_object_or_404(ProductSalesUnit, pk=pk)
|
||
|
||
if request.method == 'POST':
|
||
form = ProductSalesUnitForm(request.POST, instance=sales_unit)
|
||
if form.is_valid():
|
||
sales_unit = form.save()
|
||
messages.success(
|
||
request,
|
||
f'Единица продажи "{sales_unit.name}" успешно обновлена!'
|
||
)
|
||
return redirect('products:sales-unit-list')
|
||
else:
|
||
form = ProductSalesUnitForm(instance=sales_unit)
|
||
|
||
context = {
|
||
'form': form,
|
||
'sales_unit': sales_unit,
|
||
'title': f'Редактирование: {sales_unit.name}',
|
||
'submit_text': 'Сохранить'
|
||
}
|
||
return render(request, 'products/uom/sales_unit_form.html', context)
|
||
|
||
|
||
@login_required
|
||
def product_sales_unit_delete(request, pk):
|
||
"""
|
||
Удаление единицы продажи
|
||
"""
|
||
sales_unit = get_object_or_404(ProductSalesUnit, pk=pk)
|
||
|
||
if request.method == 'POST':
|
||
product_name = sales_unit.product.name
|
||
unit_name = sales_unit.name
|
||
sales_unit.delete()
|
||
messages.success(
|
||
request,
|
||
f'Единица продажи "{unit_name}" для товара "{product_name}" успешно удалена!'
|
||
)
|
||
return redirect('products:sales-unit-list')
|
||
|
||
context = {
|
||
'sales_unit': sales_unit,
|
||
}
|
||
return render(request, 'products/uom/sales_unit_delete.html', context)
|