Files
octopus/myproject/customers/templates/customers/customer_detail.html
Andrey Smakotin e7ac4bd8a8 Исправлено отображение статуса заказов и пагинация истории
- Исправлен баг отображения статуса: теперь сравнение с order.status.code вместо order.status
- Добавлена обработка отсутствующего статуса (показывает 'Без статуса')
- Пагинация истории заказов: добавлен якорь #ordersHistoryCollapse ко всем ссылкам
- Автооткрытие collapse при переходе по пагинации через JavaScript
- Плавная прокрутка к секции истории после раскрытия collapse (событие shown.bs.collapse)
- Пользователь остаётся в секции истории заказов при переходе между страницами
2025-11-29 19:27:08 +03:00

411 lines
24 KiB
HTML
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.
{% extends "base.html" %}
{% block title %}{{ customer.full_name }}{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-3">
<h1>Клиент: {{ customer.full_name }}</h1>
<div>
<a href="{% url 'customers:customer-update' customer.pk %}" class="btn btn-primary">Редактировать</a>
<a href="{% url 'customers:customer-delete' customer.pk %}" class="btn btn-danger">Удалить</a>
<a href="{% url 'customers:customer-list' %}" class="btn btn-secondary">Назад к списку</a>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Customer Info -->
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">
<h5>Информация о клиенте</h5>
</div>
<div class="card-body">
<table class="table table-borderless">
<tr>
<th>Имя:</th>
<td>{{ customer.full_name }}</td>
</tr>
<tr>
<th>Email:</th>
<td>{{ customer.email|default:"Не указано" }}</td>
</tr>
<tr>
<th>Телефон:</th>
<td>{{ customer.phone|default:"Не указано" }}</td>
</tr>
<tr>
<th>Сумма покупок:</th>
<td>{{ customer.total_spent|floatformat:2 }} руб.</td>
</tr>
<tr>
<th>Общий долг по активным заказам:</th>
<td>
{% if total_debt > 0 %}
<span class="text-danger fw-bold">{{ total_debt|floatformat:2 }} руб.</span>
<small class="text-muted">(Кол-во заказов: {{ active_orders_count }})</small>
{% else %}
<span class="text-success">0.00 руб.</span>
{% endif %}
</td>
</tr>
<tr>
<th>Заметки:</th>
<td>{{ customer.notes|default:"Нет" }}</td>
</tr>
<tr>
<th>Дата создания:</th>
<td>{{ customer.created_at|date:"d.m.Y H:i" }}</td>
</tr>
<tr>
<th>Дата обновления:</th>
<td>{{ customer.updated_at|date:"d.m.Y H:i" }}</td>
</tr>
</table>
</div>
</div>
</div>
<!-- Операции с кошельком -->
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Операции с кошельком клиента</h5>
<span>
{% if customer.wallet_balance > 0 %}
<span class="badge bg-success" style="font-size: 1.1em;">{{ customer.wallet_balance|floatformat:2 }} руб.</span>
{% elif customer.wallet_balance == 0 %}
<span class="badge bg-secondary" style="font-size: 1.1em;">{{ customer.wallet_balance|floatformat:2 }} руб.</span>
{% else %}
<span class="badge bg-danger" style="font-size: 1.1em;">{{ customer.wallet_balance|floatformat:2 }} руб.</span>
{% endif %}
</span>
</div>
<div class="card-body">
<div class="row">
<!-- Пополнение -->
<div class="col-md-6">
<h6 class="text-success mb-3"><i class="bi bi-plus-circle"></i> Пополнение</h6>
<form method="post" action="{% url 'customers:wallet-deposit' customer.pk %}">
{% csrf_token %}
<div class="mb-3">
<label for="wallet_deposit_amount" class="form-label">Сумма, руб.</label>
<input type="number"
step="0.01"
min="0.01"
class="form-control"
id="wallet_deposit_amount"
name="amount"
placeholder="0.00"
required>
<div style="height: 1.25rem;"></div>
</div>
<div class="mb-3">
<label for="wallet_deposit_description" class="form-label">Описание</label>
<textarea class="form-control"
id="wallet_deposit_description"
name="description"
rows="2"
placeholder="Подарок, компенсация..."
required></textarea>
</div>
<button type="submit" class="btn btn-success w-100"><i class="bi bi-plus-circle"></i> Пополнить</button>
</form>
</div>
<!-- Возврат / списание -->
<div class="col-md-6">
<h6 class="text-danger mb-3"><i class="bi bi-dash-circle"></i> Списание</h6>
<form method="post" action="{% url 'customers:wallet-withdraw' customer.pk %}">
{% csrf_token %}
<div class="mb-3">
<label for="wallet_withdraw_amount" class="form-label">Сумма, руб.</label>
<input type="number"
step="0.01"
min="0.01"
max="{{ customer.wallet_balance }}"
class="form-control"
id="wallet_withdraw_amount"
name="amount"
placeholder="0.00"
required>
<small class="text-muted d-block" style="height: 1.25rem; line-height: 1.25rem;">Макс: {{ customer.wallet_balance|floatformat:2 }} р.</small>
</div>
<div class="mb-3">
<label for="wallet_withdraw_description" class="form-label">Описание</label>
<textarea class="form-control"
id="wallet_withdraw_description"
name="description"
rows="2"
placeholder="Возврат наличными..."
required></textarea>
</div>
<button type="submit" class="btn btn-danger w-100"><i class="bi bi-dash-circle"></i> Списать</button>
</form>
</div>
</div>
<div class="alert alert-info mb-0 mt-3">
<i class="bi bi-info-circle"></i> Все операции логируются в истории ниже.
</div>
</div>
</div>
</div>
<!-- История транзакций кошелька -->
<div class="col-md-12">
<div class="card mb-4">
<div class="card-header">
<button class="btn btn-link w-100 text-start text-decoration-none p-0 d-flex justify-content-between align-items-center"
type="button"
data-bs-toggle="collapse"
data-bs-target="#walletHistoryCollapse"
aria-expanded="false"
aria-controls="walletHistoryCollapse">
<h5 class="mb-0">История кошелька (последние 20)</h5>
<div>
<span class="badge bg-primary me-2">{{ wallet_transactions|length }}</span>
<i class="bi bi-chevron-down"></i>
</div>
</button>
</div>
<div class="collapse" id="walletHistoryCollapse">
<div class="card-body">
{% if wallet_transactions %}
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Дата</th>
<th>Тип</th>
<th>Сумма</th>
<th>Описание</th>
<th>Заказ</th>
<th>Создал</th>
</tr>
</thead>
<tbody>
{% for transaction in wallet_transactions %}
<tr>
<td><small>{{ transaction.created_at|date:"d.m.Y H:i" }}</small></td>
<td>
{% if transaction.transaction_type == 'deposit' %}
<span class="badge bg-success">Пополнение</span>
{% elif transaction.transaction_type == 'spend' %}
<span class="badge bg-danger">Списание</span>
{% else %}
<span class="badge bg-warning">Корректировка</span>
{% endif %}
</td>
<td>
{% if transaction.transaction_type == 'deposit' or transaction.transaction_type == 'adjustment' and transaction.amount > 0 %}
<span class="text-success fw-bold">+{{ transaction.amount|floatformat:2 }} руб.</span>
{% else %}
<span class="text-danger fw-bold">-{{ transaction.amount|floatformat:2 }} руб.</span>
{% endif %}
</td>
<td>{{ transaction.description|default:"-" }}</td>
<td>
{% if transaction.order %}
<a href="{% url 'orders:order-detail' transaction.order.order_number %}" class="btn btn-sm btn-outline-primary">
#{{ transaction.order.order_number }}
</a>
{% else %}
-
{% endif %}
</td>
<td><small>{{ transaction.created_by.username|default:"-" }}</small></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p class="text-muted mb-0">История транзакций пуста.</p>
{% endif %}
</div>
</div>
</div>
</div>
<!-- История заказов -->
<div class="col-md-12">
<div class="card mb-4">
<div class="card-header">
<button class="btn btn-link w-100 text-start text-decoration-none p-0 d-flex justify-content-between align-items-center"
type="button"
data-bs-toggle="collapse"
data-bs-target="#ordersHistoryCollapse"
aria-expanded="false"
aria-controls="ordersHistoryCollapse">
<h5 class="mb-0">История заказов</h5>
<div>
<span class="badge bg-primary me-2">{{ orders_page.paginator.count }}</span>
<a href="{% url 'orders:order-create' %}?customer={{ customer.pk }}"
class="btn btn-sm btn-success me-2"
onclick="event.stopPropagation();">
<i class="bi bi-plus-circle"></i> Новый заказ
</a>
<i class="bi bi-chevron-down"></i>
</div>
</button>
</div>
<div class="collapse" id="ordersHistoryCollapse">
<div class="card-body">
{% if orders_page %}
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th></th>
<th>Дата создания</th>
<th>Дата доставки</th>
<th>Статус</th>
<th>Оплата</th>
<th>Сумма</th>
<th>Оплачено</th>
<th>Остаток</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
{% for order in orders_page %}
<tr>
<td><strong>#{{ order.order_number }}</strong></td>
<td><small>{{ order.created_at|date:"d.m.Y H:i" }}</small></td>
<td>
{% if order.delivery_date %}
<strong>{{ order.delivery_date|date:"d.m.Y" }}</strong>
{% if order.delivery_time %}
<br><small class="text-muted">{{ order.delivery_time }}</small>
{% endif %}
{% if order.is_delivery %}
<br><span class="badge bg-info">Доставка</span>
{% else %}
<br><span class="badge bg-secondary">Самовывоз</span>
{% endif %}
{% else %}
<span class="text-muted">Не указана</span>
{% endif %}
</td>
<td>
{% if order.status %}
{% if order.status.code == 'draft' %}
<span class="badge bg-secondary">Черновик</span>
{% elif order.status.code == 'pending' %}
<span class="badge bg-warning">Ожидает</span>
{% elif order.status.code == 'in_production' %}
<span class="badge bg-info">В производстве</span>
{% elif order.status.code == 'ready' %}
<span class="badge bg-primary">Готов</span>
{% elif order.status.code == 'delivered' %}
<span class="badge bg-success">Доставлен</span>
{% elif order.status.code == 'cancelled' %}
<span class="badge bg-danger">Отменён</span>
{% else %}
<span class="badge bg-secondary">{{ order.status.name }}</span>
{% endif %}
{% else %}
<span class="badge bg-secondary">Без статуса</span>
{% 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>
{% else %}
<span class="badge bg-danger">Не оплачено</span>
{% endif %}
</td>
<td><strong>{{ order.total_amount|floatformat:2 }} руб.</strong></td>
<td>
{% if order.amount_paid > 0 %}
<span class="text-success">{{ order.amount_paid|floatformat:2 }} руб.</span>
{% else %}
<span class="text-muted">0.00 руб.</span>
{% endif %}
</td>
<td>
{% if 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>
<a href="{% url 'orders:order-detail' order.order_number %}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i>
</a>
<a href="{% url 'orders:order-update' order.order_number %}" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-pencil"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Пагинация -->
{% if orders_page.has_other_pages %}
<nav aria-label="Навигация по заказам">
<ul class="pagination justify-content-center mt-3">
{% if orders_page.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1#ordersHistoryCollapse">Первая</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ orders_page.previous_page_number }}#ordersHistoryCollapse">Предыдущая</a>
</li>
{% endif %}
<li class="page-item active">
<span class="page-link">
Страница {{ orders_page.number }} из {{ orders_page.paginator.num_pages }}
</span>
</li>
{% if orders_page.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ orders_page.next_page_number }}#ordersHistoryCollapse">Следующая</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ orders_page.paginator.num_pages }}#ordersHistoryCollapse">Последняя</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% else %}
<p class="text-muted mb-0">У клиента пока нет заказов.</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Автооткрытие collapse при наличии якоря в URL
document.addEventListener('DOMContentLoaded', function() {
const hash = window.location.hash;
if (hash === '#ordersHistoryCollapse') {
const collapseElement = document.getElementById('ordersHistoryCollapse');
if (collapseElement) {
const bsCollapse = new bootstrap.Collapse(collapseElement, {
show: true
});
// Прокручиваем к элементу после открытия collapse (с учетом анимации)
collapseElement.addEventListener('shown.bs.collapse', function() {
collapseElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, { once: true });
}
}
});
</script>
{% endblock %}