Рабочие изменения: улучшения UI, настройки и бэкенд авторизации

Собрал накопившиеся изменения из рабочей директории:

UI улучшения:
- customer_detail.html: Расширен интерфейс детальной страницы клиента
- order_detail.html: Добавлены элементы отображения деталей заказа
- order_list.html: Улучшена визуализация списка заказов

Бэкенд:
- customers/views.py: Доработаны представления для работы с клиентами
- products/views/product_views.py: Минорные правки
- user_roles/auth_backend.py: Добавлен кастомный бэкенд авторизации

Настройки:
- myproject/settings.py: Обновлены конфигурации
- .gitignore: Добавлен для игнорирования служебных файлов
- requirements.txt: Удален (вероятно заменен на poetry/pipenv)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-03 01:08:53 +03:00
parent dcfb76121d
commit 9dab280def
9 changed files with 332 additions and 46 deletions

View File

@@ -70,6 +70,28 @@
</div>
</div>
<!-- Алерт о необходимости возврата -->
{% if refund_amount > 0 %}
<div class="col-md-12">
<div class="alert alert-warning d-flex justify-content-between align-items-center mb-4" role="alert">
<div>
<h5 class="alert-heading mb-2">
<i class="bi bi-exclamation-triangle-fill"></i> Требуется возврат средств
</h5>
<p class="mb-0">
Клиент имеет отменённые заказы с внесённой оплатой.
Общая сумма к возврату: <strong>{{ refund_amount|floatformat:2 }} руб.</strong>
</p>
</div>
<div>
<span class="badge bg-warning text-dark" style="font-size: 1.2em;">
{{ refund_amount|floatformat:2 }} руб.
</span>
</div>
</div>
</div>
{% endif %}
<!-- Операции с кошельком -->
<div class="col-md-6">
<div class="card mb-4">
@@ -268,12 +290,13 @@
<th>Сумма</th>
<th>Оплачено</th>
<th>Остаток</th>
<th>Возврат</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
{% for order in orders_page %}
<tr>
<tr {% if order.status and order.status.is_negative_end and order.amount_paid > 0 %}class="table-warning"{% endif %}>
<td><strong>#{{ order.order_number }}</strong></td>
<td><small>{{ order.created_at|date:"d.m.Y H:i" }}</small></td>
<td>
@@ -313,12 +336,22 @@
{% endif %}
</td>
<td>
{% if order.payment_status == 'paid' %}
<span class="badge bg-success">Оплачено</span>
{% elif order.payment_status == 'partial' %}
<span class="badge bg-warning">Частично</span>
{% if order.is_paid %}
<span class="badge bg-success">
<i class="bi bi-check-circle"></i> Оплачено
</span>
{% elif order.status and order.status.is_negative_end and order.amount_paid > 0 %}
<span class="badge bg-warning text-dark" title="Требуется возврат: {{ order.amount_paid|floatformat:2 }} руб.">
<i class="bi bi-exclamation-triangle"></i> Возврат
</span>
{% elif order.amount_paid > 0 %}
<span class="badge bg-warning">
<i class="bi bi-exclamation-circle"></i> Частично ({{ order.amount_paid|floatformat:2 }} руб.)
</span>
{% else %}
<span class="badge bg-danger">Не оплачено</span>
<span class="badge bg-danger">
<i class="bi bi-x-circle"></i> Не оплачено
</span>
{% endif %}
</td>
<td><strong>{{ order.total_amount|floatformat:2 }} руб.</strong></td>
@@ -330,12 +363,23 @@
{% endif %}
</td>
<td>
{% if order.amount_due > 0 %}
{% if order.status and order.status.is_negative_end %}
<span class="text-muted"></span>
{% elif order.amount_due > 0 %}
<span class="text-danger fw-bold">{{ order.amount_due|floatformat:2 }} руб.</span>
{% else %}
<span class="text-success">0.00 руб.</span>
{% endif %}
</td>
<td>
{% if order.status and order.status.is_negative_end and order.amount_paid > 0 %}
<span class="badge bg-warning text-dark" title="Требуется возврат">
<i class="bi bi-exclamation-triangle"></i> {{ order.amount_paid|floatformat:2 }} руб.
</span>
{% else %}
<span class="text-muted"></span>
{% endif %}
</td>
<td>
<a href="{% url 'orders:order-detail' order.order_number %}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i>

View File

@@ -87,8 +87,13 @@ def customer_detail(request, pk):
if customer.is_system_customer:
return render(request, 'customers/customer_system.html')
# Рассчитываем общий долг по активным заказам на стороне БД
total_debt_result = customer.orders.exclude(payment_status='paid').aggregate(
# Рассчитываем общий долг по заказам на стороне БД
# Долг = все заказы КРОМЕ отмененных и полностью оплаченных
# ВКЛЮЧАЕТ завершенные заказы с неполной оплатой!
total_debt_result = customer.orders.exclude(
Q(status__is_negative_end=True) | # Отмененные → учитываются в refund_amount
Q(payment_status='paid') # Полностью оплаченные
).aggregate(
total_debt=Coalesce(
Sum(Greatest(F('total_amount') - F('amount_paid'), Value(0), output_field=DecimalField())),
Value(0),
@@ -96,9 +101,25 @@ def customer_detail(request, pk):
)
)
total_debt = total_debt_result['total_debt'] or Decimal('0')
# Количество активных заказов
active_orders_count = customer.orders.exclude(payment_status='paid').count()
# Количество заказов с долгом (с той же логикой)
active_orders_count = customer.orders.exclude(
Q(status__is_negative_end=True) |
Q(payment_status='paid')
).count()
# Сумма к возврату (отмененные заказы с оплатой)
refund_amount_result = customer.orders.filter(
status__is_negative_end=True, # Отмененные
amount_paid__gt=0 # С оплатой
).aggregate(
total_refund=Coalesce(
Sum('amount_paid'),
Value(0),
output_field=DecimalField()
)
)
refund_amount = refund_amount_result['total_refund'] or Decimal('0')
# История транзакций кошелька (последние 20)
from .models import WalletTransaction
@@ -116,6 +137,7 @@ def customer_detail(request, pk):
'customer': customer,
'total_debt': total_debt,
'active_orders_count': active_orders_count,
'refund_amount': refund_amount,
'wallet_transactions': wallet_transactions,
'orders_page': orders_page,
}