from django.contrib import admin from django.db import models from django.utils.html import format_html from .models import Customer, WalletTransaction, ContactChannel from tenants.admin_mixins import TenantAdminOnlyMixin class IsSystemCustomerFilter(admin.SimpleListFilter): title = 'Системный клиент' parameter_name = 'is_system_customer' def lookups(self, request, model_admin): return ( ('yes', 'Системный'), ('no', 'Обычный'), ) def queryset(self, request, queryset): if self.value() == 'yes': return queryset.filter(is_system_customer=True) if self.value() == 'no': return queryset.filter(is_system_customer=False) return queryset @admin.register(Customer) class CustomerAdmin(TenantAdminOnlyMixin, admin.ModelAdmin): """ Административный интерфейс для управления клиентами цветочного магазина. TenantAdminOnlyMixin - скрывает от public admin (таблица только в tenant схемах). """ list_display = ( 'full_name', 'email', 'phone', 'wallet_balance_display', 'is_system_customer', 'created_at' ) list_filter = ( IsSystemCustomerFilter, 'created_at' ) search_fields = ( 'name', 'email', 'phone' ) date_hierarchy = 'created_at' ordering = ('-created_at',) readonly_fields = ('created_at', 'updated_at', 'is_system_customer', 'wallet_balance_display') fieldsets = ( ('Основная информация', { 'fields': ('name', 'email', 'phone', 'is_system_customer') }), ('Кошелёк', { 'fields': ('wallet_balance_display',), }), ('Заметки', { 'fields': ('notes',) }), ('Даты', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) def wallet_balance_display(self, obj): """Отображение баланса кошелька с цветом""" balance = obj.wallet_balance if balance > 0: return format_html( '{} руб.', balance ) return f'{balance} руб.' wallet_balance_display.short_description = 'Баланс кошелька' def get_readonly_fields(self, request, obj=None): """Делаем все поля read-only для системного клиента""" if obj and obj.is_system_customer: # Для системного клиента все поля только для чтения return ['name', 'email', 'phone', 'is_system_customer', 'wallet_balance_display', 'notes', 'created_at', 'updated_at'] return self.readonly_fields def has_delete_permission(self, request, obj=None): """Запрет на удаление системного клиента""" if obj and obj.is_system_customer: return False return super().has_delete_permission(request, obj) def changeform_view(self, request, object_id=None, form_url='', extra_context=None): """Добавляем предупреждение для системного клиента""" extra_context = extra_context or {} if object_id: obj = self.get_object(request, object_id) if obj and obj.is_system_customer: extra_context['readonly'] = True from django.contrib import messages messages.warning(request, 'Это системный клиент. Редактирование запрещено для обеспечения корректной работы системы.') return super().changeform_view(request, object_id, form_url, extra_context) class ContactChannelInline(admin.TabularInline): """Inline для управления каналами связи клиента""" model = ContactChannel extra = 1 fields = ('channel_type', 'value', 'is_primary', 'notes') class WalletTransactionInline(admin.TabularInline): """Inline для отображения транзакций кошелька""" model = WalletTransaction extra = 0 can_delete = False readonly_fields = ('created_at', 'transaction_type', 'signed_amount', 'balance_after', 'order', 'description', 'created_by') fields = ('created_at', 'transaction_type', 'signed_amount', 'balance_after', 'order', 'description', 'created_by') ordering = ('-created_at',) def has_add_permission(self, request, obj=None): """Запрещаем ручное создание транзакций - только через сервис""" return False # Добавляем inline в CustomerAdmin CustomerAdmin.inlines = [ContactChannelInline, WalletTransactionInline] @admin.register(WalletTransaction) class WalletTransactionAdmin(TenantAdminOnlyMixin, admin.ModelAdmin): """ Админка для просмотра всех транзакций кошелька. TenantAdminOnlyMixin - скрывает от public admin. """ list_display = ('created_at', 'customer', 'transaction_type', 'amount_display', 'balance_after', 'order', 'created_by') list_filter = ('transaction_type', 'balance_category', 'created_at') search_fields = ('customer__name', 'customer__email', 'customer__phone', 'description') readonly_fields = ('customer', 'transaction_type', 'signed_amount', 'balance_category', 'balance_after', 'order', 'description', 'created_at', 'created_by') date_hierarchy = 'created_at' ordering = ('-created_at',) def amount_display(self, obj): """Отображение суммы с цветом""" amount = obj.signed_amount if amount > 0: return format_html( '+{} руб.', amount ) elif amount < 0: return format_html( '{} руб.', amount ) return f'{amount} руб.' amount_display.short_description = 'Сумма' def has_add_permission(self, request): """Запрещаем ручное создание - только через сервис""" return False def has_delete_permission(self, request, obj=None): """Запрещаем удаление - аудит должен быть неизменяем""" return False