feat: Add customer prefill from URL parameter in order creation

- Modified order_create view to read customer from GET parameter
- Pass preselected_customer to template context
- Template renders select with preselected option for Select2
- Fixed draft creation timing with callback after Select2 initialization
- Auto-create draft when customer is preselected from URL
- Graceful handling if customer not found or invalid ID
This commit is contained in:
2025-11-27 00:17:02 +03:00
parent 5ead7fdd2e
commit c62cdb0298
6 changed files with 463 additions and 19 deletions

View File

@@ -46,9 +46,11 @@
<th>Баланс кошелька:</th>
<td>
{% if customer.wallet_balance > 0 %}
<span class="text-success fw-bold">{{ customer.wallet_balance|floatformat:2 }} руб.</span>
<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">{{ customer.wallet_balance|floatformat:2 }} руб.</span>
{% else %}
{{ customer.wallet_balance|floatformat:2 }} руб.
<span class="badge bg-danger">{{ customer.wallet_balance|floatformat:2 }} руб.</span>
{% endif %}
</td>
</tr>
@@ -79,6 +81,211 @@
</div>
</div>
</div>
<!-- История транзакций кошелька -->
<div class="col-md-12">
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5>История кошелька (последние 20)</h5>
<span class="badge bg-primary">{{ wallet_transactions|length }}</span>
</div>
<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.pk %}" 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 class="col-md-12">
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5>История заказов</h5>
<div>
<span class="badge bg-primary">{{ orders_page.paginator.count }}</span>
<a href="{% url 'orders:order-create' %}?customer={{ customer.pk }}" class="btn btn-sm btn-success ms-2">
<i class="bi bi-plus-circle"></i> Новый заказ
</a>
</div>
</div>
<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 == 'draft' %}
<span class="badge bg-secondary">Черновик</span>
{% elif order.status == 'pending' %}
<span class="badge bg-warning">Ожидает</span>
{% elif order.status == 'in_production' %}
<span class="badge bg-info">В производстве</span>
{% elif order.status == 'ready' %}
<span class="badge bg-primary">Готов</span>
{% elif order.status == 'delivered' %}
<span class="badge bg-success">Доставлен</span>
{% elif order.status == 'cancelled' %}
<span class="badge bg-danger">Отменён</span>
{% else %}
<span class="badge bg-secondary">{{ order.get_status_display }}</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.pk %}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i>
</a>
<a href="{% url 'orders:order-update' order.pk %}" 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">Первая</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ orders_page.previous_page_number }}">Предыдущая</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 }}">Следующая</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ orders_page.paginator.num_pages }}">Последняя</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% else %}
<p class="text-muted mb-0">У клиента пока нет заказов.</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -89,10 +89,24 @@ def customer_detail(request, pk):
active_orders = customer.orders.exclude(payment_status='paid')
total_debt = sum(order.amount_due for order in active_orders)
# История транзакций кошелька (последние 20)
from .models import WalletTransaction
wallet_transactions = WalletTransaction.objects.filter(
customer=customer
).select_related('order', 'created_by').order_by('-created_at')[:20]
# История заказов с пагинацией
orders_list = customer.orders.all().order_by('-created_at')
paginator = Paginator(orders_list, 10) # 10 заказов на страницу
page_number = request.GET.get('page')
orders_page = paginator.get_page(page_number)
context = {
'customer': customer,
'total_debt': total_debt,
'active_orders_count': active_orders.count(),
'wallet_transactions': wallet_transactions,
'orders_page': orders_page,
}
return render(request, 'customers/customer_detail.html', context)