diff --git a/myproject/inventory/forms.py b/myproject/inventory/forms.py index 0e8fc39..d5a14c3 100644 --- a/myproject/inventory/forms.py +++ b/myproject/inventory/forms.py @@ -108,17 +108,18 @@ class WriteOffForm(forms.ModelForm): class InventoryForm(forms.ModelForm): class Meta: model = Inventory - fields = ['warehouse', 'conducted_by', 'notes'] + fields = ['warehouse', 'notes'] widgets = { 'warehouse': forms.Select(attrs={'class': 'form-control'}), - 'conducted_by': forms.TextInput(attrs={'class': 'form-control'}), 'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + # Фильтруем только активные склады (исключаем скрытые) self.fields['warehouse'].queryset = Warehouse.objects.filter(is_active=True) + # Если есть склад по умолчанию и значение не установлено явно - предвыбираем его if not self.initial.get('warehouse'): default_warehouse = Warehouse.objects.filter( diff --git a/myproject/inventory/migrations/0017_change_conducted_by_to_fk.py b/myproject/inventory/migrations/0017_change_conducted_by_to_fk.py new file mode 100644 index 0000000..0055fe5 --- /dev/null +++ b/myproject/inventory/migrations/0017_change_conducted_by_to_fk.py @@ -0,0 +1,101 @@ +# Generated manually - Change conducted_by from CharField to ForeignKey + +from django.db import migrations, models +import django.db.models.deletion + + +def migrate_conducted_by_data(apps, schema_editor): + """ + Миграция данных: для существующих записей инвентаризации + найти первого пользователя с ролью "owner" (владелец) в текущем тенанте + и проставить его UserRole. Если владельца нет - оставить NULL. + """ + Inventory = apps.get_model('inventory', 'Inventory') + UserRole = apps.get_model('user_roles', 'UserRole') + Role = apps.get_model('user_roles', 'Role') + + # Находим первого владельца в текущем тенанте + try: + owner_role = Role.objects.get(code='owner', is_system=True) + owner_user_role = UserRole.objects.filter( + role=owner_role, + is_active=True + ).first() + + if owner_user_role: + # Обновляем все существующие инвентаризации, у которых есть старое текстовое значение + # Используем conducted_by_old (переименованное поле) для проверки + Inventory.objects.exclude(conducted_by_old__isnull=True).exclude(conducted_by_old='').update( + conducted_by_new=owner_user_role + ) + except Role.DoesNotExist: + # Если нет роли - оставляем NULL + pass + + +def reverse_migration(apps, schema_editor): + """ + Откат: очищаем новое поле + """ + Inventory = apps.get_model('inventory', 'Inventory') + Inventory.objects.filter(conducted_by_new__isnull=False).update(conducted_by_new=None) + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0016_add_document_number_to_inventory'), + ('user_roles', '0001_initial'), + ] + + operations = [ + # Шаг 1: Переименовываем старое поле в conducted_by_old + migrations.RenameField( + model_name='inventory', + old_name='conducted_by', + new_name='conducted_by_old', + ), + # Шаг 2: Добавляем новое поле как ForeignKey + migrations.AddField( + model_name='inventory', + name='conducted_by_new', + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='inventories_new', + to='user_roles.userrole', + verbose_name='Провел инвентаризацию' + ), + ), + # Шаг 3: Миграция данных + migrations.RunPython( + migrate_conducted_by_data, + reverse_code=reverse_migration + ), + # Шаг 4: Удаляем старое поле + migrations.RemoveField( + model_name='inventory', + name='conducted_by_old', + ), + # Шаг 5: Переименовываем новое поле в conducted_by + migrations.RenameField( + model_name='inventory', + old_name='conducted_by_new', + new_name='conducted_by', + ), + # Шаг 6: Исправляем related_name + migrations.AlterField( + model_name='inventory', + name='conducted_by', + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='inventories', + to='user_roles.userrole', + verbose_name='Провел инвентаризацию' + ), + ), + ] + diff --git a/myproject/inventory/templates/inventory/base_inventory_minimal.html b/myproject/inventory/templates/inventory/base_inventory_minimal.html index 9b79564..5db0ec8 100644 --- a/myproject/inventory/templates/inventory/base_inventory_minimal.html +++ b/myproject/inventory/templates/inventory/base_inventory_minimal.html @@ -11,7 +11,7 @@ diff --git a/myproject/inventory/templates/inventory/inventory/inventory_detail.html b/myproject/inventory/templates/inventory/inventory/inventory_detail.html index fcfc54e..771c3a2 100644 --- a/myproject/inventory/templates/inventory/inventory/inventory_detail.html +++ b/myproject/inventory/templates/inventory/inventory/inventory_detail.html @@ -3,7 +3,9 @@ {% load static %} {% block inventory_title %}Детали инвентаризации{% endblock %} -{% block breadcrumb_current %}Инвентаризация{% endblock %} +{% block breadcrumb_current %} + Инвентаризация +{% endblock %} {% block inventory_content %} @@ -198,6 +200,9 @@ + {% endif %} @@ -241,6 +246,43 @@ + +{% if inventory.status != 'completed' %} + +{% endif %} + diff --git a/myproject/inventory/templates/inventory/inventory/inventory_form.html b/myproject/inventory/templates/inventory/inventory/inventory_form.html index 229ea60..12d27c0 100644 --- a/myproject/inventory/templates/inventory/inventory/inventory_form.html +++ b/myproject/inventory/templates/inventory/inventory/inventory_form.html @@ -1,7 +1,9 @@ {% extends 'inventory/base_inventory_minimal.html' %} {% block inventory_title %}Новая инвентаризация{% endblock %} -{% block breadcrumb_current %}Инвентаризация{% endblock %} +{% block breadcrumb_current %} + Инвентаризация +{% endblock %} {% block inventory_content %}
@@ -25,19 +27,6 @@ {% endif %}
-
- - {{ form.conducted_by }} - {% if form.conducted_by.errors %} -
- {% for error in form.conducted_by.errors %}{{ error }}{% endfor %} -
- {% endif %} - Кто проводит инвентаризацию? -
-
{% endif %} + +{% for inventory in inventories %} +{% if inventory.status != 'completed' %} + +{% endif %} +{% endfor %} +
@@ -252,5 +302,19 @@ .gap-2 { gap: 0.5rem !important; } + +.gap-1 { + gap: 0.25rem !important; +} + +/* Фиксированная ширина для контейнера кнопок действий */ +.action-buttons-container { + width: 60px; + justify-content: flex-end; +} + +.action-buttons-container .btn-icon { + flex-shrink: 0; +} {% endblock %} diff --git a/myproject/inventory/urls.py b/myproject/inventory/urls.py index 7651608..a3d3db5 100644 --- a/myproject/inventory/urls.py +++ b/myproject/inventory/urls.py @@ -12,7 +12,7 @@ from .views import ( # Inventory InventoryListView, InventoryCreateView, InventoryDetailView, InventoryLineCreateBulkView, InventoryLineAddView, InventoryLineUpdateView, InventoryLineDeleteView, - InventoryCompleteView, + InventoryCompleteView, InventoryDeleteView, # WriteOff WriteOffListView, WriteOffCreateView, WriteOffUpdateView, WriteOffDeleteView, # Transfer @@ -87,6 +87,7 @@ urlpatterns = [ path('inventory-ops//lines//update/', InventoryLineUpdateView.as_view(), name='inventory-line-update'), path('inventory-ops//lines//delete/', InventoryLineDeleteView.as_view(), name='inventory-line-delete'), path('inventory-ops//complete/', InventoryCompleteView.as_view(), name='inventory-complete'), + path('inventory-ops//delete/', InventoryDeleteView.as_view(), name='inventory-delete'), # ==================== WRITEOFF (одиночные записи) ==================== path('writeoffs/', WriteOffListView.as_view(), name='writeoff-list'), diff --git a/myproject/inventory/views/__init__.py b/myproject/inventory/views/__init__.py index d09a90d..aa3f54e 100644 --- a/myproject/inventory/views/__init__.py +++ b/myproject/inventory/views/__init__.py @@ -25,7 +25,7 @@ from .sale import SaleListView, SaleCreateView, SaleUpdateView, SaleDeleteView, from .inventory_ops import ( InventoryListView, InventoryCreateView, InventoryDetailView, InventoryLineCreateBulkView, InventoryLineAddView, InventoryLineUpdateView, - InventoryLineDeleteView, InventoryCompleteView + InventoryLineDeleteView, InventoryCompleteView, InventoryDeleteView ) from .writeoff import WriteOffListView, WriteOffCreateView, WriteOffUpdateView, WriteOffDeleteView from .writeoff_document import ( @@ -67,7 +67,7 @@ __all__ = [ # Inventory 'InventoryListView', 'InventoryCreateView', 'InventoryDetailView', 'InventoryLineCreateBulkView', 'InventoryLineAddView', 'InventoryLineUpdateView', 'InventoryLineDeleteView', - 'InventoryCompleteView', + 'InventoryCompleteView', 'InventoryDeleteView', # WriteOff 'WriteOffListView', 'WriteOffCreateView', 'WriteOffUpdateView', 'WriteOffDeleteView', # WriteOffDocument