furry/webshop/admin.py

469 lines
17 KiB
Python

"""
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('<img src="{}" style="max-height: 50px;" />', 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('<img src="{}" style="max-height: 50px;" />', 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)