Files
octopus/myproject/customers/admin.py
Andrey Smakotin 5ead7fdd2e Реализация системы кошелька клиента для переплат
- Добавлено поле wallet_balance в модель Customer
- Создана модель WalletTransaction для истории операций
- Реализован сервис WalletService с методами:
  * add_overpayment - автоматическое зачисление переплаты
  * pay_with_wallet - оплата заказа из кошелька
  * adjust_balance - ручная корректировка баланса
- Интеграция с Payment.save() для автоматической обработки переплат
- UI для оплаты из кошелька в деталях заказа
- Отображение баланса и долга на странице клиента
- Админка с inline транзакций и запретом ручного создания
- Добавлен способ оплаты account_balance
- Миграция 0004 для customers приложения
2025-11-26 14:47:11 +03:00

157 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.contrib import admin
from django.db import models
from django.utils.html import format_html
from .models import Customer, WalletTransaction
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(admin.ModelAdmin):
"""Административный интерфейс для управления клиентами цветочного магазина"""
list_display = (
'full_name',
'email',
'phone',
'wallet_balance_display',
'total_spent',
'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', 'total_spent', 'is_system_customer', 'wallet_balance')
fieldsets = (
('Основная информация', {
'fields': ('name', 'email', 'phone', 'is_system_customer')
}),
('Кошелёк', {
'fields': ('wallet_balance',),
}),
('Статистика покупок', {
'fields': ('total_spent',),
'classes': ('collapse',)
}),
('Заметки', {
'fields': ('notes',)
}),
('Даты', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def wallet_balance_display(self, obj):
"""Отображение баланса кошелька с цветом"""
if obj.wallet_balance > 0:
return format_html(
'<span style="color: green; font-weight: bold;">{} руб.</span>',
obj.wallet_balance
)
return f'{obj.wallet_balance} руб.'
wallet_balance_display.short_description = 'Баланс кошелька'
wallet_balance_display.admin_order_field = 'wallet_balance'
def get_readonly_fields(self, request, obj=None):
"""Делаем все поля read-only для системного клиента"""
if obj and obj.is_system_customer:
# Для системного клиента все поля только для чтения
return ['name', 'email', 'phone', 'total_spent', 'is_system_customer', 'wallet_balance', '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 WalletTransactionInline(admin.TabularInline):
"""
line для отображения транзакций кошелька"""
model = WalletTransaction
extra = 0
can_delete = False
readonly_fields = ('transaction_type', 'amount', 'order', 'description', 'created_at', 'created_by')
fields = ('created_at', 'transaction_type', 'amount', 'order', 'description', 'created_by')
ordering = ('-created_at',)
def has_add_permission(self, request, obj=None):
"""Запрещаем ручное создание транзакций - только через сервис"""
return False
# Добавляем inline в CustomerAdmin
CustomerAdmin.inlines = [WalletTransactionInline]
@admin.register(WalletTransaction)
class WalletTransactionAdmin(admin.ModelAdmin):
"""Админка для просмотра всех транзакций кошелька"""
list_display = ('created_at', 'customer', 'transaction_type', 'amount_display', 'order', 'created_by')
list_filter = ('transaction_type', 'created_at')
search_fields = ('customer__name', 'customer__email', 'customer__phone', 'description')
readonly_fields = ('customer', 'transaction_type', 'amount', 'order', 'description', 'created_at', 'created_by')
date_hierarchy = 'created_at'
ordering = ('-created_at',)
def amount_display(self, obj):
"""Отображение суммы с цветом"""
if obj.transaction_type == 'deposit':
return format_html(
'<span style="color: green; font-weight: bold;">+{} руб.</span>',
obj.amount
)
elif obj.transaction_type == 'spend':
return format_html(
'<span style="color: red; font-weight: bold;">-{} руб.</span>',
obj.amount
)
return f'{obj.amount} руб.'
amount_display.short_description = 'Сумма'
def has_add_permission(self, request):
"""Запрещаем ручное создание - только через сервис"""
return False
def has_delete_permission(self, request, obj=None):
"""Запрещаем удаление - аудит должен быть неизменяем"""
return False