""" Zentrale Admin-Konfiguration für Kasico Fursuit Shop """ from django.contrib import admin from django.contrib.admin import AdminSite from django.utils.html import format_html from django.urls import path from django.db.models import Count, Sum, Avg from django.utils import timezone from datetime import timedelta # Import aller Modelle from products.models import ( Product, Order, OrderItem, Review, UserProfile, FAQ, ContactMessage, CustomOrder, OrderProgress, GalleryImage ) from shop.models import ( Category, ProductType, ProductImage, ProductVariant, CustomDesign, PayPalPayment, PaymentError ) from chat.models import ( ChatRoom, ChatMessage, UserOnlineStatus, QuickResponse, ChatAnalytics ) from recommendations.models import ( UserBehavior, UserProfile as RecUserProfile, ProductSimilarity, Recommendation, RecommendationModel, ABTest, RecommendationAnalytics ) from mobile.models import MobileDevice, MobileSession from paypal_integration.models import PayPalConfig # Custom Admin Site class KasicoAdminSite(AdminSite): site_header = "🐾 Kasico Fursuit Shop Administration" site_title = "Kasico Admin" index_title = "Willkommen in der Kasico Administration" def get_app_list(self, request): """ Gruppiere Apps in logische Kategorien """ app_list = super().get_app_list(request) # Definiere App-Gruppen app_groups = { 'Shop Management': ['products', 'shop'], 'Customer Service': ['chat'], 'Analytics & ML': ['recommendations'], 'Mobile & API': ['mobile'], 'Payment & Integration': ['paypal_integration'], } # Gruppiere Apps grouped_apps = {} for app in app_list: app_name = app['app_label'] for group, apps in app_groups.items(): if app_name in apps: if group not in grouped_apps: grouped_apps[group] = [] grouped_apps[group].append(app) break else: # Apps die nicht in Gruppen sind if 'Other' not in grouped_apps: grouped_apps['Other'] = [] grouped_apps['Other'].append(app) # Flatten und sortieren final_app_list = [] for group in sorted(grouped_apps.keys()): if group != 'Other': final_app_list.extend(grouped_apps[group]) if 'Other' in grouped_apps: final_app_list.extend(grouped_apps['Other']) return final_app_list # Erstelle Admin Site Instanz admin_site = KasicoAdminSite(name='kasico_admin') # ============================================================================= # SHOP MANAGEMENT - PRODUCTS # ============================================================================= @admin.register(Product, site=admin_site) class ProductAdmin(admin.ModelAdmin): list_display = ('name', 'price', 'stock', 'fursuit_type', 'style', 'is_featured', 'is_custom_order', 'admin_image') list_filter = ('fursuit_type', 'style', 'is_featured', 'is_custom_order', 'created') search_fields = ('name', 'description') ordering = ('-created',) list_editable = ('is_featured', 'is_custom_order') readonly_fields = ('admin_image',) fieldsets = ( ('Grundinformationen', { 'fields': ('name', 'description', 'price', 'stock') }), ('Fursuit-Details', { 'fields': ('fursuit_type', 'style', 'extras_description') }), ('Status & Features', { 'fields': ('is_featured', 'is_custom_order', 'image') }), ('Vorschau', { 'fields': ('admin_image',), 'classes': ('collapse',) }), ) def admin_image(self, obj): if obj.image: return format_html('', obj.image.url) return "Kein Bild" admin_image.short_description = 'Vorschau' @admin.register(Category, site=admin_site) class CategoryAdmin(admin.ModelAdmin): list_display = ('name', 'slug', 'parent', 'product_count') list_filter = ('parent',) search_fields = ('name',) prepopulated_fields = {'slug': ('name',)} def product_count(self, obj): return obj.products.count() product_count.short_description = 'Produkte' @admin.register(GalleryImage, site=admin_site) class GalleryImageAdmin(admin.ModelAdmin): list_display = ('title', 'fursuit_type', 'style', 'is_featured', 'order', 'created', 'admin_image') list_filter = ('fursuit_type', 'style', 'is_featured') search_fields = ('title', 'description') ordering = ('order', '-created') list_editable = ('order', 'is_featured') readonly_fields = ('admin_image',) def admin_image(self, obj): if obj.image: return format_html('', obj.image.url) return "Kein Bild" admin_image.short_description = 'Vorschau' # ============================================================================= # SHOP MANAGEMENT - ORDERS # ============================================================================= class OrderItemInline(admin.TabularInline): model = OrderItem extra = 0 readonly_fields = ('product_name', 'price') @admin.register(Order, site=admin_site) class OrderAdmin(admin.ModelAdmin): list_display = ('id', 'full_name', 'total_amount', 'status', 'payment_status', 'payment_method', 'created') list_filter = ('status', 'payment_status', 'payment_method', 'created') search_fields = ('full_name', 'email', 'id') ordering = ('-created',) readonly_fields = ('id', 'created', 'total_amount') inlines = [OrderItemInline] fieldsets = ( ('Bestellinformationen', { 'fields': ('id', 'user', 'full_name', 'email', 'phone', 'address') }), ('Zahlung & Status', { 'fields': ('status', 'payment_status', 'payment_method', 'total_amount') }), ('Zeitstempel', { 'fields': ('created',), 'classes': ('collapse',) }), ) actions = ['mark_as_paid', 'mark_as_shipped'] def mark_as_paid(self, request, queryset): updated = queryset.update(payment_status='paid') self.message_user(request, f'{updated} Bestellungen als bezahlt markiert.') mark_as_paid.short_description = "Als bezahlt markieren" def mark_as_shipped(self, request, queryset): updated = queryset.update(status='shipped') self.message_user(request, f'{updated} Bestellungen als versendet markiert.') mark_as_shipped.short_description = "Als versendet markieren" @admin.register(CustomOrder, site=admin_site) class CustomOrderAdmin(admin.ModelAdmin): list_display = ('character_name', 'user', 'fursuit_type', 'style', 'budget_range', 'status', 'created') list_filter = ('fursuit_type', 'style', 'status', 'budget_range', 'created') search_fields = ('character_name', 'user__username', 'character_description') ordering = ('-created',) readonly_fields = ('created',) fieldsets = ( ('Character & Design', { 'fields': ('character_name', 'character_description', 'fursuit_type', 'style') }), ('Kunde & Budget', { 'fields': ('user', 'budget_range', 'deadline_request') }), ('Details & Dateien', { 'fields': ('color_preferences', 'special_requests', 'reference_images') }), ('Status', { 'fields': ('status', 'created') }), ) @admin.register(OrderProgress, site=admin_site) class OrderProgressAdmin(admin.ModelAdmin): list_display = ('custom_order', 'stage', 'completed', 'created') list_filter = ('stage', 'completed', 'created') search_fields = ('custom_order__character_name', 'description') ordering = ('custom_order', 'created') # ============================================================================= # CUSTOMER SERVICE # ============================================================================= @admin.register(ContactMessage, site=admin_site) class ContactMessageAdmin(admin.ModelAdmin): list_display = ('subject', 'name', 'email', 'category', 'status', 'created') list_filter = ('category', 'status', 'created') search_fields = ('name', 'email', 'subject', 'message') ordering = ('-created',) readonly_fields = ('created',) fieldsets = ( ('Nachricht', { 'fields': ('subject', 'name', 'email', 'category', 'message') }), ('Status & Notizen', { 'fields': ('status', 'staff_notes') }), ('Zeitstempel', { 'fields': ('created',), 'classes': ('collapse',) }), ) actions = ['mark_as_in_progress', 'mark_as_resolved'] def mark_as_in_progress(self, request, queryset): updated = queryset.update(status='in_progress') self.message_user(request, f'{updated} Nachrichten als in Bearbeitung markiert.') mark_as_in_progress.short_description = "Als in Bearbeitung markieren" def mark_as_resolved(self, request, queryset): updated = queryset.update(status='resolved') self.message_user(request, f'{updated} Nachrichten als erledigt markiert.') mark_as_resolved.short_description = "Als erledigt markieren" @admin.register(ChatRoom, site=admin_site) class ChatRoomAdmin(admin.ModelAdmin): list_display = ('id', 'customer', 'admin', 'status', 'subject', 'last_message_at', 'message_count') list_filter = ('status', 'created_at') search_fields = ('customer__username', 'admin__username', 'subject') ordering = ('-last_message_at',) readonly_fields = ('id', 'created_at', 'last_message_at') def message_count(self, obj): return obj.messages.count() message_count.short_description = 'Nachrichten' @admin.register(ChatMessage, site=admin_site) class ChatMessageAdmin(admin.ModelAdmin): list_display = ('chat_room', 'sender', 'message_type', 'content_preview', 'created_at') list_filter = ('message_type', 'created_at') search_fields = ('content', 'sender__username') ordering = ('-created_at',) readonly_fields = ('created_at',) @admin.register(QuickResponse, site=admin_site) class QuickResponseAdmin(admin.ModelAdmin): list_display = ('title', 'category', 'is_active', 'use_count', 'created_by') list_filter = ('category', 'is_active', 'created_at') search_fields = ('title', 'content') ordering = ('category', 'title') # ============================================================================= # ANALYTICS & ML # ============================================================================= @admin.register(UserBehavior, site=admin_site) class UserBehaviorAdmin(admin.ModelAdmin): list_display = ('user', 'behavior_type', 'product', 'created_at') list_filter = ('behavior_type', 'created_at') search_fields = ('user__username', 'product__name') ordering = ('-created_at',) readonly_fields = ('created_at',) @admin.register(Recommendation, site=admin_site) class RecommendationAdmin(admin.ModelAdmin): list_display = ('user', 'product', 'recommendation_type', 'confidence_score', 'is_clicked', 'is_purchased') list_filter = ('recommendation_type', 'is_clicked', 'is_purchased', 'created_at') search_fields = ('user__username', 'product__name') ordering = ('-created_at',) readonly_fields = ('created_at',) @admin.register(RecommendationModel, site=admin_site) class RecommendationModelAdmin(admin.ModelAdmin): list_display = ('model_name', 'model_type', 'model_version', 'accuracy_score', 'is_active', 'trained_at') list_filter = ('model_type', 'is_active', 'trained_at') search_fields = ('model_name',) readonly_fields = ('created_at', 'trained_at') fieldsets = ( ('Model Info', { 'fields': ('model_type', 'model_name', 'model_version', 'model_file') }), ('Performance', { 'fields': ('training_data_size', 'accuracy_score', 'precision_score', 'recall_score', 'f1_score') }), ('Status', { 'fields': ('is_active', 'created_at', 'trained_at') }), ) # ============================================================================= # MOBILE & API # ============================================================================= @admin.register(MobileDevice, site=admin_site) class MobileDeviceAdmin(admin.ModelAdmin): list_display = ('user', 'device_type', 'device_name', 'is_active', 'last_seen') list_filter = ('device_type', 'is_active', 'created_at') search_fields = ('user__username', 'device_name', 'device_token') ordering = ('-created_at',) readonly_fields = ('created_at', 'last_seen') # ============================================================================= # PAYMENT & INTEGRATION # ============================================================================= @admin.register(PayPalConfig, site=admin_site) class PayPalConfigAdmin(admin.ModelAdmin): list_display = ('get_mode', 'client_id', 'is_sandbox', 'updated_at') readonly_fields = ('created_at', 'updated_at') fieldsets = ( ('API Konfiguration', { 'fields': ('client_id', 'client_secret', 'is_sandbox') }), ('Zeitstempel', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) # ============================================================================= # USERS & PROFILES # ============================================================================= @admin.register(UserProfile, site=admin_site) class UserProfileAdmin(admin.ModelAdmin): list_display = ('user', 'phone', 'newsletter', 'created') list_filter = ('newsletter', 'created') search_fields = ('user__username', 'phone', 'address') ordering = ('-created',) readonly_fields = ('created',) @admin.register(Review, site=admin_site) class ReviewAdmin(admin.ModelAdmin): list_display = ('product', 'user', 'rating', 'created') list_filter = ('rating', 'created') search_fields = ('comment', 'user__username', 'product__name') ordering = ('-created',) readonly_fields = ('created',) @admin.register(FAQ, site=admin_site) class FAQAdmin(admin.ModelAdmin): list_display = ('question', 'category', 'order') list_filter = ('category',) search_fields = ('question', 'answer') ordering = ('category', 'order') list_editable = ('order',) # ============================================================================= # DASHBOARD & STATISTICS # ============================================================================= class DashboardAdmin(admin.ModelAdmin): def get_urls(self): urls = super().get_urls() custom_urls = [ path('dashboard/', self.admin_site.admin_view(self.dashboard_view), name='dashboard'), ] return custom_urls + urls def dashboard_view(self, request): # Dashboard Statistiken context = { 'total_orders': Order.objects.count(), 'total_products': Product.objects.count(), 'total_users': UserProfile.objects.count(), 'recent_orders': Order.objects.order_by('-created')[:5], 'low_stock_products': Product.objects.filter(stock__lte=5), 'pending_contacts': ContactMessage.objects.filter(status='new'), } return render(request, 'admin/dashboard.html', context) # Registriere Dashboard admin_site.register(DashboardAdmin, DashboardAdmin) # ============================================================================= # ADMIN ACTIONS # ============================================================================= @admin.action(description="Produkte als hervorgehoben markieren") def mark_featured(modeladmin, request, queryset): updated = queryset.update(is_featured=True) modeladmin.message_user(request, f'{updated} Produkte als hervorgehoben markiert.') @admin.action(description="Lagerbestand auf 0 setzen") def set_stock_zero(modeladmin, request, queryset): updated = queryset.update(stock=0) modeladmin.message_user(request, f'{updated} Produkte auf Lagerbestand 0 gesetzt.') # Füge Actions zu Admin-Klassen hinzu ProductAdmin.actions = [mark_featured, set_stock_zero] # ============================================================================= # ADMIN SITE REGISTRATION # ============================================================================= # Registriere alle Modelle bei der neuen Admin Site admin_site.register(OrderItem) admin_site.register(Cart) admin_site.register(CartItem) admin_site.register(ProductType) admin_site.register(ProductImage) admin_site.register(ProductVariant) admin_site.register(CustomDesign) admin_site.register(PayPalPayment) admin_site.register(PaymentError) admin_site.register(ChatMessage) admin_site.register(UserOnlineStatus) admin_site.register(ChatAnalytics) admin_site.register(RecUserProfile) admin_site.register(ProductSimilarity) admin_site.register(ABTest) admin_site.register(RecommendationAnalytics) admin_site.register(MobileSession)