Реализация системы кошелька клиента для переплат

- Добавлено поле wallet_balance в модель Customer
- Создана модель WalletTransaction для истории операций
- Реализован сервис WalletService с методами:
  * add_overpayment - автоматическое зачисление переплаты
  * pay_with_wallet - оплата заказа из кошелька
  * adjust_balance - ручная корректировка баланса
- Интеграция с Payment.save() для автоматической обработки переплат
- UI для оплаты из кошелька в деталях заказа
- Отображение баланса и долга на странице клиента
- Админка с inline транзакций и запретом ручного создания
- Добавлен способ оплаты account_balance
- Миграция 0004 для customers приложения
This commit is contained in:
2025-11-26 14:47:11 +03:00
parent 0653ec0545
commit 5ead7fdd2e
16 changed files with 1401 additions and 3 deletions

View File

@@ -236,6 +236,64 @@
<!-- Правая колонка -->
<div class="col-md-4">
<!-- Кошелёк клиента -->
{% if order.customer and order.customer.wallet_balance > 0 and order.amount_due > 0 %}
<div class="card mb-3 border-success">
<div class="card-header bg-success text-white">
<h5 class="mb-0">Кошелёк клиента</h5>
</div>
<div class="card-body">
<p class="mb-2">
<strong>Баланс:</strong>
<span class="h5 text-success">{{ order.customer.wallet_balance|floatformat:2 }} руб.</span>
</p>
<p class="text-muted small">Можно использовать для оплаты этого заказа</p>
<!-- Кнопка "Применить максимум" -->
<form method="post" action="{% url 'orders:apply-wallet' order.pk %}" class="mb-2">
{% csrf_token %}
<input type="hidden" name="wallet_amount" value="{% if order.customer.wallet_balance < order.amount_due %}{{ order.customer.wallet_balance|floatformat:2 }}{% else %}{{ order.amount_due|floatformat:2 }}{% endif %}">
<button type="submit" class="btn btn-success w-100">
<i class="bi bi-wallet2"></i> Применить максимум
</button>
</form>
<!-- Ручной ввод суммы -->
<form method="post" action="{% url 'orders:apply-wallet' order.pk %}">
{% csrf_token %}
<div class="input-group">
<input
type="number"
step="0.01"
min="0"
max="{% if order.customer.wallet_balance < order.amount_due %}{{ order.customer.wallet_balance|floatformat:2 }}{% else %}{{ order.amount_due|floatformat:2 }}{% endif %}"
name="wallet_amount"
class="form-control"
placeholder="Сумма"
>
<button type="submit" class="btn btn-outline-success">
Оплатить
</button>
</div>
<small class="text-muted">Введите сумму для списания из кошелька</small>
</form>
</div>
</div>
{% elif order.customer and order.customer.wallet_balance > 0 %}
<div class="card mb-3">
<div class="card-header">
<h5 class="mb-0">Кошелёк клиента</h5>
</div>
<div class="card-body">
<p class="mb-0">
<strong>Баланс:</strong>
<span class="h5 text-success">{{ order.customer.wallet_balance|floatformat:2 }} руб.</span>
</p>
<small class="text-muted">Заказ уже оплачен полностью</small>
</div>
</div>
{% endif %}
<!-- Оплата -->
<div class="card mb-3">
<div class="card-header">