diff --git a/myproject/orders/admin.py b/myproject/orders/admin.py index ee0d85e..ddef171 100644 --- a/myproject/orders/admin.py +++ b/myproject/orders/admin.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from django.contrib import admin -from .models import Order, OrderItem, Payment, Address +from django.utils.html import format_html +from .models import Order, OrderItem, Payment, Address, OrderStatus class PaymentInline(admin.TabularInline): @@ -278,3 +279,100 @@ class AddressAdmin(admin.ModelAdmin): 'classes': ('collapse',) }), ) + + +@admin.register(OrderStatus) +class OrderStatusAdmin(admin.ModelAdmin): + """ + Админ-панель для управления статусами заказов. + """ + list_display = [ + 'order_display', + 'name', + 'code', + 'color_preview', + 'is_system', + 'is_positive_end', + 'is_negative_end', + 'orders_count', + ] + + list_filter = [ + 'is_system', + 'is_positive_end', + 'is_negative_end', + ] + + search_fields = [ + 'name', + 'code', + 'label', + ] + + readonly_fields = ['created_at', 'updated_at', 'created_by', 'updated_by'] + + fieldsets = ( + ('Основная информация', { + 'fields': ('code', 'name', 'label', 'order') + }), + ('Визуальное оформление', { + 'fields': ('color',) + }), + ('Тип статуса', { + 'fields': ('is_system', 'is_positive_end', 'is_negative_end') + }), + ('Дополнительно', { + 'fields': ('description',), + 'classes': ('collapse',) + }), + ('Системная информация', { + 'fields': ('created_at', 'updated_at', 'created_by', 'updated_by', 'get_orders_count'), + 'classes': ('collapse',) + }), + ) + + ordering = ['order', 'name'] + + def get_readonly_fields(self, request, obj=None): + """Делаем код readonly для системных статусов""" + readonly = list(self.readonly_fields) + readonly.append('get_orders_count') + if obj and obj.is_system: + readonly.append('code') + return readonly + + def color_preview(self, obj): + """Превью цвета статуса""" + return format_html( + '
', + obj.color + ) + color_preview.short_description = 'Цвет' + + def order_display(self, obj): + """Отображение порядкового номера с бейджем""" + return format_html( + '{}', + obj.order + ) + order_display.short_description = 'Порядок' + + def orders_count(self, obj): + """Количество заказов в этом статусе""" + count = obj.orders_count + if count == 0: + return format_html('{}', count) + return format_html('{}', count) + orders_count.short_description = 'Заказов' + + def get_orders_count(self, obj): + """Количество заказов для readonly поля""" + return obj.orders_count if obj else 0 + get_orders_count.short_description = 'Количество заказов' + + def has_delete_permission(self, request, obj=None): + """Запрещаем удаление системных статусов и статусов с заказами""" + if obj: + if obj.is_system or obj.orders_count > 0: + return False + return super().has_delete_permission(request, obj) diff --git a/myproject/orders/migrations/0003_update_status_names_to_russian.py b/myproject/orders/migrations/0003_update_status_names_to_russian.py new file mode 100644 index 0000000..2f80b02 --- /dev/null +++ b/myproject/orders/migrations/0003_update_status_names_to_russian.py @@ -0,0 +1,64 @@ +# Generated by Django 5.0.10 on 2025-11-13 14:19 + +from django.db import migrations + + +def update_status_names_to_russian(apps, schema_editor): + """Обновляем названия статусов на русский язык""" + OrderStatus = apps.get_model('orders', 'OrderStatus') + + status_translations = { + 'draft': 'Черновик', + 'new': 'Новый', + 'confirmed': 'Подтвережден', + 'in_assembly': 'В сборке', + 'in_delivery': 'В доставке', + 'completed': 'Выполнен', + 'return': 'Возврат', + 'cancelled': 'Отменен', + } + + for code, russian_name in status_translations.items(): + try: + status = OrderStatus.objects.get(code=code) + status.name = russian_name + status.label = russian_name + status.save() + except OrderStatus.DoesNotExist: + pass + + +def reverse_status_names(apps, schema_editor): + """Откатываем названия статусов обратно на английский (для отката миграции)""" + OrderStatus = apps.get_model('orders', 'OrderStatus') + + status_translations = { + 'draft': 'Draft', + 'new': 'New', + 'confirmed': 'Confirmed', + 'in_assembly': 'In Assembly', + 'in_delivery': 'In Delivery', + 'completed': 'Completed', + 'return': 'Return', + 'cancelled': 'Cancelled', + } + + for code, english_name in status_translations.items(): + try: + status = OrderStatus.objects.get(code=code) + status.name = english_name + status.label = english_name + status.save() + except OrderStatus.DoesNotExist: + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('orders', '0002_initial'), + ] + + operations = [ + migrations.RunPython(update_status_names_to_russian, reverse_status_names), + ] diff --git a/myproject/orders/models.py b/myproject/orders/models.py index f6912ae..bd0e0b7 100644 --- a/myproject/orders/models.py +++ b/myproject/orders/models.py @@ -99,6 +99,11 @@ class OrderStatus(models.Model): def __str__(self): return self.name + @property + def orders_count(self): + """Количество заказов в этом статусе""" + return self.orders.count() + class Address(models.Model): """