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

@@ -10,7 +10,7 @@ from django.db.models.functions import Coalesce
from itertools import chain
from ..models import Product, ProductCategory, ProductTag, ProductKit
from ..forms import ProductForm
from ..forms import ProductForm, ProductSalesUnitFormSet
from .utils import handle_photos
from ..models import ProductPhoto
from user_roles.mixins import ManagerOwnerRequiredMixin
@@ -110,11 +110,36 @@ class ProductCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, CreateVie
def get_success_url(self):
return reverse_lazy('products:products-list')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.POST:
context['sales_unit_formset'] = ProductSalesUnitFormSet(
self.request.POST,
prefix='sales_units'
)
else:
context['sales_unit_formset'] = ProductSalesUnitFormSet(prefix='sales_units')
return context
def form_valid(self, form):
from django.db import IntegrityError
context = self.get_context_data()
sales_unit_formset = context['sales_unit_formset']
try:
response = super().form_valid(form)
# Сначала сохраняем товар
self.object = form.save()
# Затем сохраняем единицы продажи
if sales_unit_formset.is_valid():
sales_unit_formset.instance = self.object
sales_unit_formset.save()
else:
# Если formset невалиден, показываем ошибки
for error in sales_unit_formset.errors:
if error:
messages.warning(self.request, f'Ошибка в единицах продажи: {error}')
# Обработка загрузки фотографий
photo_errors = handle_photos(self.request, self.object, ProductPhoto, 'product')
@@ -127,7 +152,7 @@ class ProductCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, CreateVie
messages.error(self.request, error)
messages.success(self.request, f'Товар "{form.instance.name}" успешно создан!')
return response
return super().form_valid(form)
except IntegrityError as e:
# Обработка ошибки дублирования slug'а или других unique constraints
@@ -161,7 +186,7 @@ class ProductDetailView(LoginRequiredMixin, ManagerOwnerRequiredMixin, DetailVie
'photos',
'categories',
'tags',
'sales_units__unit'
'sales_units'
).annotate(
total_available=total_available,
total_reserved=total_reserved,
@@ -199,13 +224,40 @@ class ProductUpdateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, UpdateVie
# Добавляем фотографии товара в контекст
context['product_photos'] = self.object.photos.all().order_by('order', 'created_at')
context['photos_count'] = self.object.photos.count()
# Добавляем formset единиц продажи
if self.request.POST:
context['sales_unit_formset'] = ProductSalesUnitFormSet(
self.request.POST,
instance=self.object,
prefix='sales_units'
)
else:
context['sales_unit_formset'] = ProductSalesUnitFormSet(
instance=self.object,
prefix='sales_units'
)
return context
def form_valid(self, form):
from django.db import IntegrityError
context = self.get_context_data()
sales_unit_formset = context['sales_unit_formset']
try:
response = super().form_valid(form)
# Сначала сохраняем товар
self.object = form.save()
# Затем сохраняем единицы продажи
if sales_unit_formset.is_valid():
sales_unit_formset.instance = self.object
sales_unit_formset.save()
else:
# Если formset невалиден, показываем ошибки
for error in sales_unit_formset.errors:
if error:
messages.warning(self.request, f'Ошибка в единицах продажи: {error}')
# Обработка загрузки фотографий
photo_errors = handle_photos(self.request, self.object, ProductPhoto, 'product')
@@ -218,7 +270,7 @@ class ProductUpdateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, UpdateVie
messages.error(self.request, error)
messages.success(self.request, f'Товар "{form.instance.name}" успешно обновлен!')
return response
return super().form_valid(form)
except IntegrityError as e:
# Обработка ошибки дублирования slug'а или других unique constraints