Удаление заказа теперь блокируется если есть связанные WalletTransaction (on_delete=PROTECT). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
446 lines
24 KiB
HTML
446 lines
24 KiB
HTML
{% extends 'base.html' %}
|
||
|
||
{% block title %}Заказ {{ order.order_number }}{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="container-fluid">
|
||
<div class="row mb-4">
|
||
<div class="col">
|
||
<h1>
|
||
Заказ {{ order.order_number }}
|
||
{% if order.status %}
|
||
<span class="badge ms-2" style="background-color: {{ order.status.color }}; color: #fff;">
|
||
{{ order.status.label|default:order.status.name }}
|
||
</span>
|
||
{% else %}
|
||
<span class="badge bg-secondary ms-2">Не установлен</span>
|
||
{% endif %}
|
||
{% if order.is_returned %}
|
||
<span class="badge bg-danger ms-2">
|
||
<i class="bi bi-arrow-counterclockwise"></i> Возвращен
|
||
</span>
|
||
{% endif %}
|
||
</h1>
|
||
</div>
|
||
<div class="col-auto">
|
||
<a href="{% url 'orders:order-update' order.order_number %}" class="btn btn-primary">
|
||
<i class="bi bi-pencil"></i> Редактировать
|
||
</a>
|
||
{% if order.status and order.status.code == 'draft' and order.amount_paid == 0 and not order.wallet_transactions.exists %}
|
||
<a href="{% url 'orders:order-delete' order.order_number %}" class="btn btn-danger">
|
||
<i class="bi bi-trash"></i> Удалить
|
||
</a>
|
||
{% endif %}
|
||
<a href="{% url 'orders:order-list' %}" class="btn btn-secondary">
|
||
<i class="bi bi-arrow-left"></i> К списку
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<!-- Левая колонка -->
|
||
<div class="col-md-8">
|
||
<!-- Товары -->
|
||
<div class="card mb-3">
|
||
<div class="card-header">
|
||
<h5 class="mb-0">Товары в заказе</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<table class="table">
|
||
<thead>
|
||
<tr>
|
||
<th>Наименование</th>
|
||
<th>Количество</th>
|
||
<th>Цена</th>
|
||
<th>Сумма</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for item in order.items.all %}
|
||
<tr>
|
||
<td>
|
||
{{ item.item_name }}
|
||
{% if item.product_kit and item.product_kit.is_temporary %}
|
||
<span class="badge bg-info ms-1">Временный</span>
|
||
<br>
|
||
<small class="text-muted">Создан специально для этого заказа</small>
|
||
<br>
|
||
<a href="{% url 'products:productkit-make-permanent' item.product_kit.pk %}" class="btn btn-sm btn-outline-success mt-1">
|
||
<i class="bi bi-arrow-right-circle"></i> Сделать постоянным
|
||
</a>
|
||
{% endif %}
|
||
</td>
|
||
<td>{{ item.quantity }} шт.</td>
|
||
<td>
|
||
{{ item.price|floatformat:2 }} руб.
|
||
{% if item.is_custom_price %}
|
||
<span class="badge bg-warning ms-1">Изменена</span>
|
||
<br>
|
||
<small class="text-muted">
|
||
Оригинальная: {{ item.original_price|floatformat:2 }} руб.
|
||
{% if item.price_difference %}
|
||
{% if item.price_difference > 0 %}
|
||
<span class="text-success">(+{{ item.price_difference|floatformat:2 }} руб.)</span>
|
||
{% else %}
|
||
<span class="text-danger">({{ item.price_difference|floatformat:2 }} руб.)</span>
|
||
{% endif %}
|
||
{% endif %}
|
||
</small>
|
||
{% endif %}
|
||
</td>
|
||
<td><strong>{{ item.get_total_price|floatformat:2 }} руб.</strong></td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Основная информация -->
|
||
<div class="card mb-3">
|
||
<div class="card-header">
|
||
<h5 class="mb-0">Информация о заказе</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Клиент:</strong></div>
|
||
<div class="col-md-8">
|
||
<a href="{% url 'customers:customer-detail' order.customer.pk %}">
|
||
{{ order.customer.name }}
|
||
</a>
|
||
</div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Телефон:</strong></div>
|
||
<div class="col-md-8">{{ order.customer.phone }}</div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Статус:</strong></div>
|
||
<div class="col-md-8">
|
||
{% if order.status %}
|
||
<span class="badge" style="background-color: {{ order.status.color }}; color: #fff;">
|
||
{{ order.status.label|default:order.status.name }}
|
||
</span>
|
||
{% else %}
|
||
<span class="badge bg-secondary">Не установлен</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Создан:</strong></div>
|
||
<div class="col-md-8">{{ order.created_at|date:"d.m.Y H:i" }}</div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Обновлен:</strong></div>
|
||
<div class="col-md-8">{{ order.updated_at|date:"d.m.Y H:i" }}</div>
|
||
</div>
|
||
{% if order.modified_by %}
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Изменен:</strong></div>
|
||
<div class="col-md-8">
|
||
{{ order.modified_by.get_short_name|default:order.modified_by.username }}
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
{% if order.is_draft and order.last_autosave_at %}
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Последнее автосохранение:</strong></div>
|
||
<div class="col-md-8">{{ order.last_autosave_at|date:"d.m.Y H:i" }}</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Получатель -->
|
||
{% if order.recipient %}
|
||
<div class="card mb-3">
|
||
<div class="card-header">
|
||
<h5 class="mb-0">Получатель</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Имя получателя:</strong></div>
|
||
<div class="col-md-8">{{ order.recipient.name|default:"Не указано" }}</div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Телефон получателя:</strong></div>
|
||
<div class="col-md-8">{{ order.recipient.phone|default:"Не указан" }}</div>
|
||
</div>
|
||
{% if order.is_anonymous %}
|
||
<div class="row mb-2">
|
||
<div class="col-md-12">
|
||
<span class="badge bg-warning">Анонимная доставка</span>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- Доставка -->
|
||
<div class="card mb-3">
|
||
<div class="card-header">
|
||
<h5 class="mb-0">Доставка</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Тип:</strong></div>
|
||
<div class="col-md-8">
|
||
{% if order.is_delivery %}
|
||
<span class="badge bg-info">Доставка курьером</span>
|
||
{% else %}
|
||
<span class="badge bg-secondary">Самовывоз</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% if order.is_delivery %}
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Адрес:</strong></div>
|
||
<div class="col-md-8">
|
||
{% if order.delivery_address %}
|
||
{{ order.delivery_address.full_address }}
|
||
{% else %}
|
||
<span class="text-danger">Не указан</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Стоимость доставки:</strong></div>
|
||
<div class="col-md-8">{{ order.delivery_cost|floatformat:2 }} руб.</div>
|
||
</div>
|
||
{% else %}
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Склад для самовывоза:</strong></div>
|
||
<div class="col-md-8">
|
||
{% if order.pickup_warehouse %}
|
||
{{ order.pickup_warehouse.name }}<br>
|
||
<small class="text-muted">{{ order.pickup_warehouse.full_address }}</small>
|
||
{% else %}
|
||
<span class="text-danger">Не указан</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Дата:</strong></div>
|
||
<div class="col-md-8">
|
||
{% if order.delivery_date %}
|
||
{{ order.delivery_date|date:"d.m.Y" }}
|
||
{% else %}
|
||
<span class="text-muted">Не указана</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Время:</strong></div>
|
||
<div class="col-md-8">
|
||
{% if order.delivery_time_start and order.delivery_time_end %}
|
||
{{ order.delivery_time_window }}
|
||
{% else %}
|
||
<span class="text-muted">Не указано</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% if order.needs_product_photo or order.needs_delivery_photo %}
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Требования к фото:</strong></div>
|
||
<div class="col-md-8">
|
||
{% if order.needs_product_photo %}
|
||
<span class="badge bg-info me-2">
|
||
<i class="bi bi-camera"></i> Фото товара
|
||
</span>
|
||
{% endif %}
|
||
{% if order.needs_delivery_photo %}
|
||
<span class="badge bg-info">
|
||
<i class="bi bi-camera-video"></i> Фото вручения
|
||
</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
{% if order.special_instructions %}
|
||
<div class="row mb-2">
|
||
<div class="col-md-4"><strong>Особые пожелания:</strong></div>
|
||
<div class="col-md-8">{{ order.special_instructions }}</div>
|
||
</div>
|
||
{% endif %}
|
||
{% if order.is_anonymous %}
|
||
<div class="row mb-2">
|
||
<div class="col-md-12">
|
||
<span class="badge bg-warning">Анонимная доставка</span>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Правая колонка -->
|
||
<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.order_number %}" 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.order_number %}">
|
||
{% 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">
|
||
<h5 class="mb-0">Оплата</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row mb-2">
|
||
<div class="col-6"><strong>Товары:</strong></div>
|
||
<div class="col-6 text-end">{{ order.subtotal|floatformat:2 }} руб.</div>
|
||
</div>
|
||
{% if order.is_delivery %}
|
||
<div class="row mb-2">
|
||
<div class="col-6"><strong>Доставка:</strong></div>
|
||
<div class="col-6 text-end">{{ order.delivery_cost|floatformat:2 }} руб.</div>
|
||
</div>
|
||
{% endif %}
|
||
<hr>
|
||
<div class="row mb-3">
|
||
<div class="col-6"><strong>Итого:</strong></div>
|
||
<div class="col-6 text-end"><h5>{{ order.total_amount|floatformat:2 }} руб.</h5></div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-6"><strong>Оплачено:</strong></div>
|
||
<div class="col-6 text-end">{{ order.amount_paid|floatformat:2 }} руб.</div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-6"><strong>К оплате:</strong></div>
|
||
<div class="col-6 text-end text-danger"><strong>{{ order.amount_due|floatformat:2 }} руб.</strong></div>
|
||
</div>
|
||
<div class="row mb-2">
|
||
<div class="col-12">
|
||
<strong>Статус оплаты:</strong>
|
||
{% if order.payment_status == 'paid' %}
|
||
<span class="badge bg-success w-100">Оплачен полностью</span>
|
||
{% elif order.payment_status == 'partial' %}
|
||
<span class="badge bg-warning w-100">Частично оплачен</span>
|
||
{% else %}
|
||
<span class="badge bg-danger w-100">Не оплачен</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Предупреждение о необходимости возврата -->
|
||
{% if order.status and order.status.is_negative_end and order.amount_paid > 0 %}
|
||
<hr>
|
||
<div class="alert alert-warning mb-0">
|
||
<h6 class="alert-heading">
|
||
<i class="bi bi-exclamation-triangle-fill"></i> Требуется возврат
|
||
</h6>
|
||
<p class="mb-0">
|
||
Заказ отменён, но клиент внёс оплату: <strong>{{ order.amount_paid|floatformat:2 }} руб.</strong>
|
||
</p>
|
||
<small class="text-muted d-block mt-2">
|
||
<i class="bi bi-info-circle"></i> Создайте возврат через раздел "История транзакций" ниже
|
||
</small>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- История транзакций -->
|
||
{% if order.transactions.exists %}
|
||
<div class="card mb-3">
|
||
<div class="card-header">
|
||
<h5 class="mb-0">История транзакций</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<ul class="list-group list-group-flush">
|
||
{% for transaction in order.transactions.all|dictsortreversed:"transaction_date" %}
|
||
<li class="list-group-item">
|
||
<div class="d-flex justify-content-between align-items-start">
|
||
<div>
|
||
<strong class="{% if transaction.transaction_type == 'payment' %}text-success{% else %}text-danger{% endif %}">
|
||
{% if transaction.transaction_type == 'refund' %}−{% else %}+{% endif %}{{ transaction.amount|floatformat:2 }} руб.
|
||
</strong>
|
||
</div>
|
||
<div>
|
||
{% if transaction.transaction_type == 'payment' %}
|
||
<span class="badge bg-success">Платёж</span>
|
||
{% else %}
|
||
<span class="badge bg-warning text-dark">Возврат</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
<small class="text-muted">
|
||
{{ transaction.transaction_date|date:"d.m.Y H:i" }}<br>
|
||
{% if transaction.transaction_type == 'refund' and transaction.payment_method.code == 'account_balance' %}
|
||
Возврат на баланс счёта
|
||
{% else %}
|
||
{{ transaction.payment_method.name }}
|
||
{% endif %}
|
||
{% if transaction.notes or transaction.reason %}
|
||
<br><em>{{ transaction.notes|default:transaction.reason }}</em>
|
||
{% endif %}
|
||
{% if transaction.created_by %}
|
||
<br>Кем: {{ transaction.created_by.get_short_name|default:transaction.created_by.username }}
|
||
{% endif %}
|
||
</small>
|
||
</li>
|
||
{% endfor %}
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|