feat: упростить создание заказов и рефакторинг единиц измерения

- Добавить inline-редактирование цен в списке товаров
- Оптимизировать карточки товаров в POS-терминале
- Рефакторинг моделей единиц измерения
- Миграция unit -> base_unit в SalesUnit
- Улучшить UI форм создания/редактирования товаров

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-17 03:34:43 +03:00
parent 928b340486
commit 2f1f0621e6
24 changed files with 1079 additions and 227 deletions

View File

@@ -9,7 +9,7 @@ from django.core.paginator import Paginator
from django.urls import reverse
from products.models import UnitOfMeasure, ProductSalesUnit
from products.forms import ProductSalesUnitForm
from products.forms import ProductSalesUnitForm, UnitOfMeasureForm
@login_required
@@ -26,7 +26,8 @@ def unit_of_measure_list(request):
# Аннотируем количество использований
units = units.annotate(
usage_count=Count('productsalesunit')
usage_count=Count('productsalesunit'),
products_count=Count('products')
)
# Применяем фильтры
@@ -58,6 +59,89 @@ def unit_of_measure_list(request):
return render(request, 'products/uom/unit_list.html', context)
@login_required
def unit_of_measure_create(request):
"""
Создание новой единицы измерения
"""
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):
"""
Редактирование единицы измерения
"""
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):
"""
Удаление единицы измерения
"""
unit = get_object_or_404(UnitOfMeasure, pk=pk)
# Проверяем использование
products_using = unit.products.count()
sales_units_using = unit.productsalesunit_set.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):
"""
@@ -65,14 +149,11 @@ def product_sales_unit_list(request):
"""
# Получаем параметры фильтрации
search_query = request.GET.get('q', '').strip()
unit_filter = request.GET.get('unit', '')
is_active_filter = request.GET.get('is_active', '')
is_default_filter = request.GET.get('is_default', '')
# Базовый queryset
sales_units = ProductSalesUnit.objects.select_related(
'product', 'unit'
).all()
sales_units = ProductSalesUnit.objects.select_related('product').all()
# Применяем фильтры
if search_query:
@@ -82,9 +163,6 @@ def product_sales_unit_list(request):
Q(name__icontains=search_query)
)
if unit_filter:
sales_units = sales_units.filter(unit_id=unit_filter)
if is_active_filter:
sales_units = sales_units.filter(is_active=(is_active_filter == 'true'))
@@ -99,16 +177,11 @@ def product_sales_unit_list(request):
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
# Для фильтра единиц
all_units = UnitOfMeasure.objects.filter(is_active=True).order_by('position', 'code')
context = {
'page_obj': page_obj,
'search_query': search_query,
'unit_filter': unit_filter,
'is_active_filter': is_active_filter,
'is_default_filter': is_default_filter,
'all_units': all_units,
'total_sales_units': sales_units.count(),
}