Add full CRUD interface for Showcase management
Implemented complete web interface for managing showcases (display areas for ready-made bouquets) with: **Backend:** - ShowcaseForm with validation (unique name per warehouse) - ShowcaseListView with filtering by warehouse and status - ShowcaseCreateView, ShowcaseUpdateView with success messages - ShowcaseDeleteView with active reservation validation - URL routes: list, create, edit, delete **Frontend:** - List page with warehouse grouping, active reservations count - Responsive table with filters (warehouse, status) - Create/edit form with Bootstrap styling - Delete confirmation with active reservations check - Breadcrumb navigation **Features:** ✅ One warehouse can have multiple showcases (ForeignKey relationship) ✅ Unique showcase names within each warehouse ✅ Display active reservation counts for each showcase ✅ Prevent deletion if showcase has active reservations ✅ Auto-select default warehouse when creating showcase ✅ Navigation link added to main navbar between "Касса" and "Склад" ✅ Active state highlighting in navigation **Files created:** - inventory/forms_showcase.py (ShowcaseForm) - inventory/views/showcase.py (4 CBV views) - inventory/templates/inventory/showcase/ (list, form, delete templates) **Files modified:** - inventory/urls.py (added showcase routes) - inventory/forms.py (added Showcase import) - templates/navbar.html (added "Витрины" link) URL structure: /inventory/showcases/ - list /inventory/showcases/create/ - create /inventory/showcases/<id>/edit/ - edit /inventory/showcases/<id>/delete/ - delete 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
73
myproject/inventory/forms_showcase.py
Normal file
73
myproject/inventory/forms_showcase.py
Normal file
@@ -0,0 +1,73 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from .models import Showcase, Warehouse
|
||||
|
||||
|
||||
class ShowcaseForm(forms.ModelForm):
|
||||
"""
|
||||
Форма для создания и редактирования витрин.
|
||||
Витрина привязывается к складу и используется для выкладки готовых букетов.
|
||||
"""
|
||||
class Meta:
|
||||
model = Showcase
|
||||
fields = ['name', 'warehouse', 'description', 'is_active']
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': 'Название витрины (например: Витрина №1, Витрина у входа)'
|
||||
}),
|
||||
'warehouse': forms.Select(attrs={'class': 'form-control'}),
|
||||
'description': forms.Textarea(attrs={
|
||||
'class': 'form-control',
|
||||
'rows': 3,
|
||||
'placeholder': 'Описание витрины, её расположение или особенности'
|
||||
}),
|
||||
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
||||
}
|
||||
labels = {
|
||||
'name': 'Название витрины',
|
||||
'warehouse': 'Склад',
|
||||
'description': 'Описание',
|
||||
'is_active': 'Активна',
|
||||
}
|
||||
help_texts = {
|
||||
'warehouse': 'Склад, к которому привязана витрина',
|
||||
'is_active': 'Неактивные витрины скрыты из списка выбора',
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# Фильтруем только активные склады
|
||||
self.fields['warehouse'].queryset = Warehouse.objects.filter(is_active=True).order_by('name')
|
||||
|
||||
# Если создаём новую витрину и есть склад по умолчанию - предвыбираем его
|
||||
if not self.instance.pk and not self.initial.get('warehouse'):
|
||||
default_warehouse = Warehouse.objects.filter(
|
||||
is_active=True,
|
||||
is_default=True
|
||||
).first()
|
||||
if default_warehouse:
|
||||
self.initial['warehouse'] = default_warehouse.id
|
||||
|
||||
def clean_name(self):
|
||||
"""Проверка уникальности названия витрины в рамках склада"""
|
||||
name = self.cleaned_data.get('name')
|
||||
warehouse = self.cleaned_data.get('warehouse')
|
||||
|
||||
if name and warehouse:
|
||||
# Проверяем уникальность названия в рамках склада
|
||||
queryset = Showcase.objects.filter(name=name, warehouse=warehouse)
|
||||
|
||||
# При редактировании исключаем текущий экземпляр
|
||||
if self.instance and self.instance.pk:
|
||||
queryset = queryset.exclude(pk=self.instance.pk)
|
||||
|
||||
if queryset.exists():
|
||||
raise ValidationError(
|
||||
f'Витрина с названием "{name}" уже существует на складе "{warehouse.name}". '
|
||||
'Пожалуйста, выберите другое название.'
|
||||
)
|
||||
|
||||
return name
|
||||
Reference in New Issue
Block a user