From f89e715c80051bd49ca4e5590fcde2aeb97bc57e Mon Sep 17 00:00:00 2001 From: thomas Date: Sun, 6 Jul 2025 09:54:09 +0200 Subject: [PATCH] =?UTF-8?q?Complete=20Admin-Backend=20Overhaul=20-=20Neue?= =?UTF-8?q?=20zentrale=20Admin-Site=20mit=20besserer=20Strukturierung=20un?= =?UTF-8?q?d=20=C3=9Cbersichtlichkeit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- products/admin.py | 92 +------ shop/admin.py | 125 +-------- templates/admin/dashboard.html | 219 +++++++++++++++ webshop/admin.py | 469 +++++++++++++++++++++++++++++++++ webshop/urls.py | 3 +- 5 files changed, 694 insertions(+), 214 deletions(-) create mode 100644 templates/admin/dashboard.html create mode 100644 webshop/admin.py diff --git a/products/admin.py b/products/admin.py index 9559829..6db3618 100644 --- a/products/admin.py +++ b/products/admin.py @@ -1,90 +1,2 @@ -from django.contrib import admin -from .models import ( - Product, Cart, CartItem, Order, OrderItem, - Review, UserProfile, FAQ, ContactMessage, - CustomOrder, OrderProgress, GalleryImage -) -from django.utils.safestring import mark_safe - -@admin.register(Product) -class ProductAdmin(admin.ModelAdmin): - list_display = ('name', 'price', 'stock', 'fursuit_type', 'style', 'is_featured', 'is_custom_order') - list_filter = ('fursuit_type', 'style', 'is_featured', 'is_custom_order') - search_fields = ('name', 'description') - ordering = ('-created',) - -@admin.register(Order) -class OrderAdmin(admin.ModelAdmin): - list_display = ('id', 'full_name', 'total_amount', 'status', 'payment_status', 'created') - list_filter = ('status', 'payment_status', 'payment_method') - search_fields = ('full_name', 'email') - ordering = ('-created',) - -@admin.register(OrderItem) -class OrderItemAdmin(admin.ModelAdmin): - list_display = ('order', 'product_name', 'quantity', 'price') - search_fields = ('product_name',) - -@admin.register(Review) -class ReviewAdmin(admin.ModelAdmin): - list_display = ('product', 'user', 'rating', 'created') - list_filter = ('rating',) - search_fields = ('comment', 'user__username') - -@admin.register(Cart) -class CartAdmin(admin.ModelAdmin): - list_display = ('id', 'user', 'created') - search_fields = ('user__username',) - -@admin.register(CartItem) -class CartItemAdmin(admin.ModelAdmin): - list_display = ('cart', 'product', 'quantity') - -@admin.register(UserProfile) -class UserProfileAdmin(admin.ModelAdmin): - list_display = ('user', 'phone', 'newsletter') - list_filter = ('newsletter',) - search_fields = ('user__username', 'phone', 'address') - -@admin.register(FAQ) -class FAQAdmin(admin.ModelAdmin): - list_display = ('question', 'category', 'order') - list_filter = ('category',) - search_fields = ('question', 'answer') - ordering = ('category', 'order') - -@admin.register(ContactMessage) -class ContactMessageAdmin(admin.ModelAdmin): - list_display = ('subject', 'name', 'email', 'category', 'status', 'created') - list_filter = ('category', 'status') - search_fields = ('name', 'email', 'subject', 'message') - ordering = ('-created',) - -@admin.register(CustomOrder) -class CustomOrderAdmin(admin.ModelAdmin): - list_display = ('character_name', 'user', 'fursuit_type', 'status', 'created') - list_filter = ('fursuit_type', 'style', 'status') - search_fields = ('character_name', 'user__username', 'character_description') - ordering = ('-created',) - -@admin.register(OrderProgress) -class OrderProgressAdmin(admin.ModelAdmin): - list_display = ('custom_order', 'stage', 'completed', 'created') - list_filter = ('stage', 'completed') - search_fields = ('custom_order__character_name', 'description') - ordering = ('custom_order', 'created') - -@admin.register(GalleryImage) -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 mark_safe(f'') - return "Kein Bild" - admin_image.short_description = 'Vorschau' +# Diese Datei ist jetzt leer, da alle Admin-Konfigurationen in webshop/admin.py zentral verwaltet werden +# Die Admin-Konfigurationen wurden in die neue zentrale Admin-Site verschoben diff --git a/shop/admin.py b/shop/admin.py index 4481a5e..622bb25 100644 --- a/shop/admin.py +++ b/shop/admin.py @@ -1,123 +1,2 @@ -from django.contrib import admin -from django.utils.translation import gettext_lazy as _ -from django.utils.html import format_html -from .models import ( - Product, Category, FursuitGallery, GalleryImage, - DesignTemplate, CustomerDesign, Order, OrderProgress, - Cart, CartItem, ShippingAddress, Checkout, - ProductType, ProductImage, ProductVariant, CustomDesign, - PayPalPayment, PaymentError -) - -@admin.register(Category) -class CategoryAdmin(admin.ModelAdmin): - list_display = ['name', 'slug', 'parent'] - list_filter = ['parent'] - search_fields = ['name'] - prepopulated_fields = {'slug': ('name',)} - -@admin.register(ProductType) -class ProductTypeAdmin(admin.ModelAdmin): - list_display = ['name', 'has_sizes', 'has_colors', 'has_custom_design', 'requires_measurements'] - list_filter = ['has_sizes', 'has_colors', 'has_custom_design', 'requires_measurements'] - search_fields = ['name'] - -class ProductImageInline(admin.TabularInline): - model = ProductImage - extra = 1 - -class ProductVariantInline(admin.TabularInline): - model = ProductVariant - extra = 1 - -@admin.register(Product) -class ProductAdmin(admin.ModelAdmin): - list_display = ['name', 'category', 'price', 'stock', 'available', 'created'] - list_filter = ['available', 'category', 'product_type', 'created'] - search_fields = ['name', 'description'] - prepopulated_fields = {'slug': ('name',)} - inlines = [ProductImageInline, ProductVariantInline] - date_hierarchy = 'created' - -@admin.register(CustomDesign) -class CustomDesignAdmin(admin.ModelAdmin): - list_display = ['product', 'customer', 'status', 'created'] - list_filter = ['status', 'created'] - search_fields = ['product__name', 'customer__username'] - date_hierarchy = 'created' - -@admin.register(DesignTemplate) -class DesignTemplateAdmin(admin.ModelAdmin): - list_display = ['name', 'created_at'] - search_fields = ['name', 'description'] - -@admin.register(CustomerDesign) -class CustomerDesignAdmin(admin.ModelAdmin): - list_display = ['user', 'name', 'created_at'] - search_fields = ['user__username', 'name'] - date_hierarchy = 'created_at' - -class OrderProgressInline(admin.TabularInline): - model = OrderProgress - extra = 1 - -@admin.register(Order) -class OrderAdmin(admin.ModelAdmin): - list_display = ['id', 'user', 'product', 'status', 'payment_method', 'total_price', 'created_at'] - list_filter = ['status', 'payment_method', 'created_at'] - search_fields = ['user__username', 'product__name'] - inlines = [OrderProgressInline] - date_hierarchy = 'created_at' - -class CartItemInline(admin.TabularInline): - model = CartItem - extra = 1 - -@admin.register(Cart) -class CartAdmin(admin.ModelAdmin): - list_display = ['user', 'created_at', 'updated_at'] - search_fields = ['user__username'] - inlines = [CartItemInline] - date_hierarchy = 'created_at' - -@admin.register(ShippingAddress) -class ShippingAddressAdmin(admin.ModelAdmin): - list_display = ['user', 'first_name', 'last_name', 'city', 'country'] - list_filter = ['country'] - search_fields = ['user__username', 'first_name', 'last_name', 'city'] - -@admin.register(Checkout) -class CheckoutAdmin(admin.ModelAdmin): - list_display = ['user', 'status', 'payment_method', 'created_at'] - list_filter = ['status', 'payment_method'] - search_fields = ['user__username'] - date_hierarchy = 'created_at' - -@admin.register(PayPalPayment) -class PayPalPaymentAdmin(admin.ModelAdmin): - list_display = ['order', 'payment_id', 'status', 'amount', 'currency', 'created_at'] - list_filter = ['status', 'currency'] - search_fields = ['payment_id', 'order__id'] - date_hierarchy = 'created_at' - -@admin.register(PaymentError) -class PaymentErrorAdmin(admin.ModelAdmin): - list_display = ['order', 'error_code', 'created_at'] - search_fields = ['order__id', 'error_code', 'error_message'] - date_hierarchy = 'created_at' - -@admin.register(FursuitGallery) -class FursuitGalleryAdmin(admin.ModelAdmin): - list_display = ['name', 'created_at'] - search_fields = ['name', 'description'] - prepopulated_fields = {'slug': ('name',)} - -class GalleryImageInline(admin.TabularInline): - model = GalleryImage - extra = 1 - -@admin.register(GalleryImage) -class GalleryImageAdmin(admin.ModelAdmin): - list_display = ['gallery', 'title', 'order'] - list_filter = ['gallery'] - search_fields = ['gallery__name', 'title'] +# Diese Datei ist jetzt leer, da alle Admin-Konfigurationen in webshop/admin.py zentral verwaltet werden +# Die Admin-Konfigurationen wurden in die neue zentrale Admin-Site verschoben diff --git a/templates/admin/dashboard.html b/templates/admin/dashboard.html new file mode 100644 index 0000000..8333e22 --- /dev/null +++ b/templates/admin/dashboard.html @@ -0,0 +1,219 @@ +{% extends "admin/base_site.html" %} +{% load static %} + +{% block title %}Dashboard - Kasico Administration{% endblock %} + +{% block extrastyle %} + +{% endblock %} + +{% block content %} +
+

🐾 Kasico Dashboard

+ + +
+
+

Gesamtbestellungen

+
{{ total_orders }}
+
+12% diese Woche
+
+ +
+

Produkte

+
{{ total_products }}
+
{{ low_stock_products.count }} niedriger Lagerbestand
+
+ +
+

Kunden

+
{{ total_users }}
+
+5% diesen Monat
+
+ +
+

Offene Anfragen

+
{{ pending_contacts.count }}
+
Neue Nachrichten
+
+
+ +
+ +
+

📦 Letzte Bestellungen

+ {% for order in recent_orders %} +
+
+ #{{ order.id }} - {{ order.full_name }} +
+ {{ order.created|date:"d.m.Y H:i" }} +
+
+ + {{ order.get_payment_status_display }} + +
+ {{ order.total_amount }}€ +
+
+ {% empty %} +

Keine Bestellungen vorhanden

+ {% endfor %} +
+ + +
+

⚠️ Niedriger Lagerbestand

+ {% for product in low_stock_products %} +
+
+ {{ product.name }} +
+ {{ product.get_fursuit_type_display }} • {{ product.get_style_display }} +
+
+ + {{ product.stock }} Stück + +
+
+ {% empty %} +

Alle Produkte verfügbar

+ {% endfor %} +
+
+ + + +
+{% endblock %} \ No newline at end of file diff --git a/webshop/admin.py b/webshop/admin.py new file mode 100644 index 0000000..d6bc091 --- /dev/null +++ b/webshop/admin.py @@ -0,0 +1,469 @@ +""" +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) \ No newline at end of file diff --git a/webshop/urls.py b/webshop/urls.py index 9691e8f..46d17b1 100644 --- a/webshop/urls.py +++ b/webshop/urls.py @@ -22,9 +22,10 @@ from django.contrib.auth import views as auth_views from shop import views as shop_views from products.forms import CustomAuthenticationForm from rest_framework.documentation import include_docs_urls +from .admin import admin_site urlpatterns = [ - path('admin/', admin.site.urls), + path('admin/', admin_site.urls), # Neue Admin-Site path('', include('shop.urls')), path('products/', include('products.urls')), path('paypal/', include('paypal_integration.urls')),