feat: Добавлена возможность ручного изменения цены товаров/комплектов в заказе

- Добавлено поле is_custom_price в модель OrderItem для отслеживания ручных изменений
- Добавлены свойства original_price и price_difference для отображения оригинальной цены и разницы
- Поле цены теперь редактируемое (убран атрибут readonly)
- Добавлены визуальные индикаторы: бейдж "Изменена" и информация об оригинальной цене
- JavaScript автоматически отслеживает изменения цены и устанавливает флаг is_custom_price
- В детальном просмотре заказа показывается информация о кастомных ценах с разницей
- Цена товара в каталоге не изменяется - изменения только для конкретного заказа

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-07 10:44:46 +03:00
parent 9e430bca18
commit 2bf2afb56f
5 changed files with 1234 additions and 23 deletions

View File

@@ -0,0 +1,319 @@
{% 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 }}</h1>
</div>
<div class="col-auto">
<a href="{% url 'orders:order-update' order.pk %}" class="btn btn-primary">
<i class="bi bi-pencil"></i> Редактировать
</a>
<a href="{% url 'orders:order-delete' order.pk %}" class="btn btn-danger">
<i class="bi bi-trash"></i> Удалить
</a>
<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">
<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 == 'new' %}
<span class="badge bg-primary">Новый</span>
{% elif order.status == 'confirmed' %}
<span class="badge bg-success">Подтвержден</span>
{% elif order.status == 'in_assembly' %}
<span class="badge bg-warning">В сборке</span>
{% elif order.status == 'in_delivery' %}
<span class="badge bg-info">В доставке</span>
{% elif order.status == 'delivered' %}
<span class="badge bg-success">Доставлен</span>
{% elif order.status == 'cancelled' %}
<span class="badge bg-danger">Отменен</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>
</div>
</div>
<!-- Получатель -->
{% if not order.customer_is_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 }} руб.</div>
</div>
{% else %}
<div class="row mb-2">
<div class="col-md-4"><strong>Точка самовывоза:</strong></div>
<div class="col-md-8">
{% if order.pickup_shop %}
{{ order.pickup_shop.name }}<br>
<small class="text-muted">{{ order.pickup_shop.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.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 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 }}</td>
<td>{{ item.quantity }}</td>
<td>
{{ item.price }} руб.
{% if item.is_custom_price %}
<span class="badge bg-warning ms-1">Изменена</span>
<br>
<small class="text-muted">
Оригинальная: {{ item.original_price }} руб.
{% if item.price_difference %}
{% if item.price_difference > 0 %}
<span class="text-success">(+{{ item.price_difference }} руб.)</span>
{% else %}
<span class="text-danger">({{ item.price_difference }} руб.)</span>
{% endif %}
{% endif %}
</small>
{% endif %}
</td>
<td><strong>{{ item.get_total_price }} руб.</strong></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- Правая колонка -->
<div class="col-md-4">
<!-- Оплата -->
<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">
{% with items_total=order.items.all|length %}
{% if items_total > 0 %}
{{ order.total_amount|floatformat:2 }} руб.
{% else %}
0.00 руб.
{% endif %}
{% endwith %}
</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 }} руб.</div>
</div>
{% endif %}
{% if order.discount_amount > 0 %}
<div class="row mb-2">
<div class="col-6"><strong>Скидка:</strong></div>
<div class="col-6 text-end text-danger">-{{ order.discount_amount }} руб.</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 }} руб.</h5></div>
</div>
<div class="row mb-2">
<div class="col-6"><strong>Оплачено:</strong></div>
<div class="col-6 text-end">{{ order.amount_paid }} руб.</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 }} руб.</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>
<div class="row mb-2">
<div class="col-12">
<strong>Способ оплаты:</strong><br>
{{ order.get_payment_method_display }}
</div>
</div>
</div>
</div>
<!-- История платежей -->
{% if order.payments.all %}
<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 payment in order.payments.all %}
<li class="list-group-item">
<div><strong>{{ payment.amount }} руб.</strong></div>
<small class="text-muted">
{{ payment.payment_date|date:"d.m.Y H:i" }}<br>
{{ payment.get_payment_method_display }}
{% if payment.created_by %}
<br>Принял: {{ payment.created_by.get_full_name }}
{% endif %}
</small>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}