""" Админ-панель для реферальной системы. """ from django.contrib import admin from django.utils.html import format_html from .models import ( ReferralSettings, ReferralLevel, UserReferralProfile, BonusAccount, ReferralEarning, PointsTransaction, BonusTransaction, PromoCode, PromoCodeUsage, ReferralInvitedEmail, UserActivityDay, PendingReferralBonus, ) @admin.register(ReferralSettings) class ReferralSettingsAdmin(admin.ModelAdmin): """Админ для настроек реферальной программы.""" list_display = [ 'level1_commission', 'level2_commission', 'points_direct_referral', 'points_indirect_referral', 'updated_at' ] fieldsets = ( ('Комиссии', { 'fields': ('level1_commission', 'level2_commission') }), ('Очки', { 'fields': ('points_direct_referral', 'points_indirect_referral') }), ) @admin.register(ReferralLevel) class ReferralLevelAdmin(admin.ModelAdmin): """Админ для уровней реферальной программы.""" list_display = ['level', 'name', 'points_required', 'bonus_payment_percent', 'icon'] list_editable = ['bonus_payment_percent'] ordering = ['level'] @admin.register(UserReferralProfile) class UserReferralProfileAdmin(admin.ModelAdmin): """Админ для реферальных профилей.""" list_display = [ 'user_email', 'referral_code', 'referred_by_email', 'current_level', 'total_points', 'direct_referrals_count', 'total_earned', 'created_at' ] list_filter = ['current_level', 'created_at'] search_fields = ['user__email', 'referral_code', 'referred_by__email'] readonly_fields = [ 'referral_code', 'total_points', 'direct_referrals_count', 'indirect_referrals_count', 'total_earned', 'created_at', 'updated_at', 'referral_link' ] fieldsets = ( ('Основная информация', { 'fields': ('user', 'referral_code', 'referred_by', 'referral_link') }), ('Уровень и очки', { 'fields': ('current_level', 'total_points') }), ('Статистика', { 'fields': ( 'direct_referrals_count', 'indirect_referrals_count', 'total_earned' ) }), ('Даты', { 'fields': ('created_at', 'updated_at') }), ) def user_email(self, obj): return obj.user.email user_email.short_description = 'Email' def referred_by_email(self, obj): return obj.referred_by.email if obj.referred_by else '-' referred_by_email.short_description = 'Пригласил' def referral_link(self, obj): link = obj.get_referral_link() return format_html('{}', link, link) referral_link.short_description = 'Реферальная ссылка' @admin.register(BonusAccount) class BonusAccountAdmin(admin.ModelAdmin): """Админ для бонусных счетов.""" list_display = [ 'user_email', 'balance', 'total_earned', 'total_spent', 'updated_at' ] list_editable = ['balance'] search_fields = ['user__email'] readonly_fields = ['created_at', 'updated_at'] fieldsets = ( ('Основная информация', { 'fields': ('user',) }), ('Баланс и статистика', { 'fields': ('balance', 'total_earned', 'total_spent'), 'description': 'Внимание: изменение баланса напрямую не создает транзакцию в истории. ' 'Для корректного учета используйте методы add_bonus() и spend_bonus() модели.' }), ('Временные метки', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) def user_email(self, obj): return obj.user.email user_email.short_description = 'Email' def save_model(self, request, obj, form, change): """ Сохранить модель с логированием изменений. """ if change: # Получаем старые значения для логирования old_obj = BonusAccount.objects.get(pk=obj.pk) # Логируем изменения баланса if old_obj.balance != obj.balance: from .models import BonusTransaction from decimal import Decimal diff = obj.balance - old_obj.balance if diff != 0: transaction_type = 'earn' if diff > 0 else 'spend' BonusTransaction.objects.create( user=obj.user, amount=abs(diff), transaction_type=transaction_type, reason=f'Ручное изменение баланса администратором {request.user.email}', balance_after=obj.balance ) # Обновляем статистику if diff > 0: obj.total_earned += diff else: obj.total_spent += abs(diff) # Логируем изменения статистики (если изменены напрямую) if old_obj.total_earned != obj.total_earned or old_obj.total_spent != obj.total_spent: # Если статистика изменена напрямую, просто сохраняем pass super().save_model(request, obj, form, change) @admin.register(ReferralEarning) class ReferralEarningAdmin(admin.ModelAdmin): """Админ для заработков с рефералов.""" list_display = [ 'referrer_email', 'referral_email', 'level', 'payment_amount', 'commission_percent', 'earned_amount', 'created_at' ] list_filter = ['level', 'created_at'] search_fields = ['referrer__email', 'referral__email'] readonly_fields = [ 'referrer', 'referral', 'payment', 'level', 'payment_amount', 'commission_percent', 'earned_amount', 'created_at' ] def referrer_email(self, obj): return obj.referrer.email referrer_email.short_description = 'Реферер' def referral_email(self, obj): return obj.referral.email referral_email.short_description = 'Реферал' @admin.register(PointsTransaction) class PointsTransactionAdmin(admin.ModelAdmin): """Админ для транзакций очков.""" list_display = ['user_email', 'points', 'reason', 'balance_after', 'created_at'] list_filter = ['created_at'] search_fields = ['user__email', 'reason'] readonly_fields = ['user', 'points', 'reason', 'balance_after', 'created_at'] def user_email(self, obj): return obj.user.email user_email.short_description = 'Email' @admin.register(BonusTransaction) class BonusTransactionAdmin(admin.ModelAdmin): """Админ для транзакций бонусов.""" list_display = [ 'user_email', 'amount', 'transaction_type', 'reason', 'balance_after', 'created_at' ] list_filter = ['transaction_type', 'created_at'] search_fields = ['user__email', 'reason'] readonly_fields = ['user', 'amount', 'transaction_type', 'reason', 'balance_after', 'created_at'] def user_email(self, obj): return obj.user.email user_email.short_description = 'Email' @admin.register(PromoCode) class PromoCodeAdmin(admin.ModelAdmin): """Админ для промокодов.""" list_display = [ 'code', 'name', 'discount_display', 'current_uses', 'max_uses', 'valid_until', 'is_active', 'created_at' ] list_filter = ['is_active', 'discount_type', 'created_at'] search_fields = ['code', 'name', 'description'] filter_horizontal = ['applicable_plans'] fieldsets = ( ('Основная информация', { 'fields': ('code', 'name', 'description') }), ('Скидка', { 'fields': ('discount_type', 'discount_value') }), ('Применимость', { 'fields': ('applicable_plans',) }), ('Ограничения', { 'fields': ('max_uses', 'current_uses', 'valid_until', 'is_active') }), ('Метаданные', { 'fields': ('created_by', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) readonly_fields = ['current_uses', 'created_at', 'updated_at'] def discount_display(self, obj): if obj.discount_type == 'percent': return f'{obj.discount_value}%' return f'{obj.discount_value} ₽' discount_display.short_description = 'Скидка' def save_model(self, request, obj, form, change): if not change: obj.created_by = request.user super().save_model(request, obj, form, change) @admin.register(PromoCodeUsage) class PromoCodeUsageAdmin(admin.ModelAdmin): """Админ для использований промокодов.""" list_display = [ 'user_email', 'promo_code_code', 'original_amount', 'discount_amount', 'final_amount', 'created_at' ] list_filter = ['created_at', 'promo_code'] search_fields = ['user__email', 'promo_code__code'] readonly_fields = [ 'user', 'promo_code', 'payment', 'original_amount', 'discount_amount', 'final_amount', 'created_at' ] def user_email(self, obj): return obj.user.email user_email.short_description = 'Email' def promo_code_code(self, obj): return obj.promo_code.code promo_code_code.short_description = 'Промокод' @admin.register(ReferralInvitedEmail) class ReferralInvitedEmailAdmin(admin.ModelAdmin): """Бэклог приглашённых email (защита от накрутки).""" list_display = ['email', 'referrer', 'referred_user', 'created_at'] search_fields = ['email', 'referrer__email', 'referred_user__email'] readonly_fields = ['email', 'referrer', 'referred_user', 'created_at'] list_filter = ['created_at'] @admin.register(UserActivityDay) class UserActivityDayAdmin(admin.ModelAdmin): """Дни активности пользователей (для проверки условий начисления бонусов).""" list_display = ['user', 'date', 'created_at'] list_filter = ['date'] search_fields = ['user__email'] readonly_fields = ['user', 'date', 'created_at'] @admin.register(PendingReferralBonus) class PendingReferralBonusAdmin(admin.ModelAdmin): """Ожидающие начисления бонусов за рефералов.""" list_display = ['referrer', 'referred_user', 'points', 'level', 'status', 'referred_at', 'paid_at'] list_filter = ['status', 'level'] search_fields = ['referrer__email', 'referred_user__email'] readonly_fields = ['referrer', 'referred_user', 'referred_at', 'points', 'level', 'reason', 'paid_at', 'created_at']