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 %}

View File

@@ -0,0 +1,536 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row mb-4">
<div class="col">
<h1>{{ title }}</h1>
</div>
<div class="col-auto">
<a href="{% url 'orders:order-list' %}" class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> Назад к списку
</a>
</div>
</div>
<form method="post" id="order-form">
{% csrf_token %}
<!-- Основная информация -->
<div class="card mb-3">
<div class="card-header">
<h5 class="mb-0">Основная информация</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.customer.id_for_label }}" class="form-label">
Клиент <span class="text-danger">*</span>
</label>
{{ form.customer }}
{% if form.customer.errors %}
<div class="text-danger">{{ form.customer.errors }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.status.id_for_label }}" class="form-label">Статус</label>
{{ form.status }}
{% if form.status.errors %}
<div class="text-danger">{{ form.status.errors }}</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Доставка -->
<div class="card mb-3">
<div class="card-header">
<h5 class="mb-0">Доставка</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="mb-3 form-check">
{{ form.is_delivery }}
<label class="form-check-label" for="{{ form.is_delivery.id_for_label }}">
С доставкой (снимите галочку для самовывоза)
</label>
</div>
<div class="mb-3 form-check">
{{ form.customer_is_recipient }}
<label class="form-check-label" for="{{ form.customer_is_recipient.id_for_label }}">
Покупатель является получателем
</label>
</div>
</div>
</div>
<!-- Поля получателя (показываются когда покупатель != получатель) -->
<div class="row" id="recipient-fields" style="display: none;">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.recipient_name.id_for_label }}" class="form-label">
Имя получателя <span class="text-danger">*</span>
</label>
{{ form.recipient_name }}
{% if form.recipient_name.errors %}
<div class="text-danger">{{ form.recipient_name.errors }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.recipient_phone.id_for_label }}" class="form-label">
Телефон получателя <span class="text-danger">*</span>
</label>
{{ form.recipient_phone }}
{% if form.recipient_phone.errors %}
<div class="text-danger">{{ form.recipient_phone.errors }}</div>
{% endif %}
</div>
</div>
</div>
<div class="row" id="delivery-fields">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.delivery_address.id_for_label }}" class="form-label">
Адрес доставки
</label>
{{ form.delivery_address }}
{% if form.delivery_address.errors %}
<div class="text-danger">{{ form.delivery_address.errors }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.delivery_cost.id_for_label }}" class="form-label">Стоимость доставки</label>
{{ form.delivery_cost }}
{% if form.delivery_cost.errors %}
<div class="text-danger">{{ form.delivery_cost.errors }}</div>
{% endif %}
</div>
</div>
</div>
<div class="row" id="pickup-fields" style="display: none;">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.pickup_shop.id_for_label }}" class="form-label">
Точка самовывоза
</label>
{{ form.pickup_shop }}
{% if form.pickup_shop.errors %}
<div class="text-danger">{{ form.pickup_shop.errors }}</div>
{% endif %}
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="mb-3">
<label for="{{ form.delivery_date.id_for_label }}" class="form-label">Дата</label>
{{ form.delivery_date }}
{% if form.delivery_date.errors %}
<div class="text-danger">{{ form.delivery_date.errors }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="mb-3">
<label for="{{ form.delivery_time_start.id_for_label }}" class="form-label">Время от</label>
{{ form.delivery_time_start }}
{% if form.delivery_time_start.errors %}
<div class="text-danger">{{ form.delivery_time_start.errors }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="mb-3">
<label for="{{ form.delivery_time_end.id_for_label }}" class="form-label">Время до</label>
{{ form.delivery_time_end }}
{% if form.delivery_time_end.errors %}
<div class="text-danger">{{ form.delivery_time_end.errors }}</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Товары в заказе -->
<div class="card mb-3">
<div class="card-header">
<h5 class="mb-0">Товары в заказе</h5>
</div>
<div class="card-body">
{{ formset.management_form }}
<div id="order-items-container">
{% for item_form in formset %}
<div class="order-item-form border rounded p-3 mb-3" data-form-index="{{ forloop.counter0 }}">
{{ item_form.id }}
{{ item_form.product }} <!-- Hidden field -->
{{ item_form.product_kit }} <!-- Hidden field -->
{{ item_form.is_custom_price }} <!-- Hidden field -->
<div class="row align-items-end">
<div class="col-md-5">
<div class="mb-2">
<label class="form-label">Товар или комплект</label>
<select class="form-select select2-order-item" data-form-index="{{ forloop.counter0 }}">
<option value=""></option>
{% if item_form.instance.product %}
<option value="product_{{ item_form.instance.product.id }}" selected data-type="product" data-price="{{ item_form.instance.product.actual_price }}">
{{ item_form.instance.product.name }}{% if item_form.instance.product.sku %} ({{ item_form.instance.product.sku }}){% endif %}
</option>
{% elif item_form.instance.product_kit %}
<option value="kit_{{ item_form.instance.product_kit.id }}" selected data-type="kit" data-price="{{ item_form.instance.product_kit.actual_price }}">
{{ item_form.instance.product_kit.name }}{% if item_form.instance.product_kit.sku %} ({{ item_form.instance.product_kit.sku }}){% endif %}
</option>
{% endif %}
</select>
</div>
</div>
<div class="col-md-2">
<div class="mb-2">
<label class="form-label">Количество</label>
{{ item_form.quantity }}
</div>
</div>
<div class="col-md-3">
<div class="mb-2">
<label class="form-label">Цена</label>
<div class="position-relative">
{{ item_form.price }}
<span class="custom-price-badge badge bg-warning position-absolute top-0 end-0 mt-1 me-1" style="display: none;">
Изменена
</span>
<small class="text-muted original-price-info position-absolute" style="display: none; top: calc(100% + 2px); left: 0; white-space: nowrap;">
Оригинальная: <span class="original-price-value"></span> руб.
</small>
</div>
</div>
</div>
<div class="col-md-2 text-end">
{% if formset.can_delete %}
<div class="mb-2">
<div class="form-check">
{{ item_form.DELETE }}
<label class="form-check-label" for="{{ item_form.DELETE.id_for_label }}">
Удалить
</label>
</div>
</div>
{% endif %}
</div>
</div>
{% if item_form.errors %}
<div class="alert alert-danger mt-2">{{ item_form.errors }}</div>
{% endif %}
</div>
{% endfor %}
</div>
<button type="button" class="btn btn-secondary" id="add-item-btn">
<i class="bi bi-plus-circle"></i> Добавить товар
</button>
</div>
</div>
<!-- Оплата и дополнительно -->
<div class="card mb-3">
<div class="card-header">
<h5 class="mb-0">Оплата</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<div class="mb-3">
<label for="{{ form.payment_method.id_for_label }}" class="form-label">Способ оплаты</label>
{{ form.payment_method }}
</div>
</div>
<div class="col-md-4">
<div class="mb-3">
<label for="{{ form.discount_amount.id_for_label }}" class="form-label">Скидка</label>
{{ form.discount_amount }}
</div>
</div>
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
<h5 class="mb-0">Дополнительно</h5>
</div>
<div class="card-body">
<div class="mb-3 form-check">
{{ form.is_anonymous }}
<label class="form-check-label" for="{{ form.is_anonymous.id_for_label }}">
Анонимная доставка
</label>
</div>
<div class="mb-3">
<label for="{{ form.special_instructions.id_for_label }}" class="form-label">Особые пожелания</label>
{{ form.special_instructions }}
</div>
</div>
</div>
<!-- Кнопки -->
<div class="row">
<div class="col">
<button type="submit" class="btn btn-primary btn-lg">
<i class="bi bi-check-circle"></i> {{ button_text }}
</button>
<a href="{% url 'orders:order-list' %}" class="btn btn-secondary btn-lg">
<i class="bi bi-x-circle"></i> Отмена
</a>
</div>
</div>
</form>
</div>
<!-- Подключение модуля Select2 для поиска товаров/комплектов -->
<script src="{% static 'products/js/select2-product-search.js' %}"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Инициализация Select2 для обычных полей (не товары)
$('.select2:not(.select2-order-item)').select2({
theme: 'bootstrap-5',
width: '100%',
language: 'ru'
});
// Показ/скрытие полей доставки/самовывоза
const isDeliveryCheckbox = document.getElementById('{{ form.is_delivery.id_for_label }}');
const deliveryFields = document.getElementById('delivery-fields');
const pickupFields = document.getElementById('pickup-fields');
function toggleDeliveryFields() {
if (isDeliveryCheckbox.checked) {
deliveryFields.style.display = '';
pickupFields.style.display = 'none';
} else {
deliveryFields.style.display = 'none';
pickupFields.style.display = '';
}
}
isDeliveryCheckbox.addEventListener('change', toggleDeliveryFields);
toggleDeliveryFields(); // Инициализация при загрузке
// Показ/скрытие полей получателя
const customerIsRecipientCheckbox = document.getElementById('{{ form.customer_is_recipient.id_for_label }}');
const recipientFields = document.getElementById('recipient-fields');
function toggleRecipientFields() {
if (customerIsRecipientCheckbox.checked) {
recipientFields.style.display = 'none';
} else {
recipientFields.style.display = '';
}
}
customerIsRecipientCheckbox.addEventListener('change', toggleRecipientFields);
toggleRecipientFields(); // Инициализация при загрузке
// Инициализация Select2 для поиска товаров/комплектов
function initOrderItemSelect2(element) {
const $element = $(element);
const formIndex = element.dataset.formIndex;
// Инициализируем Select2 с AJAX поиском
window.initProductSelect2(
element,
'all', // Искать и товары, и комплекты
'{% url "products:api-search-products-variants" %}'
);
// Обработка выбора элемента
$element.on('select2:select', function(e) {
const data = e.params.data;
const idParts = data.id.split('_');
const type = idParts[0]; // 'product' или 'kit'
const id = idParts[1];
// Найти скрытые поля product и product_kit
const form = element.closest('.order-item-form');
const productField = form.querySelector('[name$="-product"]');
const kitField = form.querySelector('[name$="-product_kit"]');
const priceField = form.querySelector('[name$="-price"]');
const isCustomPriceField = form.querySelector('[name$="-is_custom_price"]');
const originalPrice = data.actual_price || data.price || '';
// Установить значение в правильное поле
if (type === 'product') {
productField.value = id;
kitField.value = '';
priceField.value = originalPrice;
} else if (type === 'kit') {
kitField.value = id;
productField.value = '';
priceField.value = originalPrice;
}
// Сохраняем оригинальную цену в data-атрибуте
priceField.dataset.originalPrice = originalPrice;
// Сбрасываем флаг кастомной цены
isCustomPriceField.value = 'false';
// Скрываем индикатор
const badge = form.querySelector('.custom-price-badge');
const priceInfo = form.querySelector('.original-price-info');
if (badge) badge.style.display = 'none';
if (priceInfo) priceInfo.style.display = 'none';
});
// Очистка при удалении выбора
$element.on('select2:clear', function() {
const form = element.closest('.order-item-form');
form.querySelector('[name$="-product"]').value = '';
form.querySelector('[name$="-product_kit"]').value = '';
form.querySelector('[name$="-price"]').value = '';
});
}
// Инициализировать все существующие формы товаров
document.querySelectorAll('.select2-order-item').forEach(initOrderItemSelect2);
// Функция для инициализации отслеживания изменения цены
function initPriceTracking(form) {
const priceField = form.querySelector('[name$="-price"]');
const isCustomPriceField = form.querySelector('[name$="-is_custom_price"]');
const badge = form.querySelector('.custom-price-badge');
const priceInfo = form.querySelector('.original-price-info');
const originalPriceValue = form.querySelector('.original-price-value');
if (!priceField) return;
// Отслеживание изменения цены вручную
priceField.addEventListener('input', function() {
const currentPrice = parseFloat(priceField.value) || 0;
const originalPrice = parseFloat(priceField.dataset.originalPrice) || 0;
// Если цена изменена и есть оригинальная цена
if (originalPrice && currentPrice !== originalPrice) {
isCustomPriceField.value = 'true';
badge.style.display = '';
priceInfo.style.display = '';
originalPriceValue.textContent = originalPrice.toFixed(2);
} else {
isCustomPriceField.value = 'false';
badge.style.display = 'none';
priceInfo.style.display = 'none';
}
});
// Проверка при загрузке формы (для редактирования)
if (isCustomPriceField.value === 'True' || isCustomPriceField.value === 'true') {
badge.style.display = '';
priceInfo.style.display = '';
const originalPrice = parseFloat(priceField.dataset.originalPrice) || 0;
if (originalPrice) {
originalPriceValue.textContent = originalPrice.toFixed(2);
}
}
}
// Инициализация отслеживания цены для всех существующих форм
document.querySelectorAll('.order-item-form').forEach(initPriceTracking);
// Динамическое добавление позиций товаров
const container = document.getElementById('order-items-container');
const addButton = document.getElementById('add-item-btn');
const totalFormsInput = document.querySelector('#id_items-TOTAL_FORMS');
addButton.addEventListener('click', function() {
const formCount = parseInt(totalFormsInput.value);
const lastForm = container.querySelector('.order-item-form:last-child');
const newForm = lastForm.cloneNode(true);
// Обновляем индексы в новой форме
const regex = new RegExp('items-(\\d+)-', 'g');
newForm.innerHTML = newForm.innerHTML.replace(regex, `items-${formCount}-`);
newForm.dataset.formIndex = formCount;
// Очищаем значения
newForm.querySelectorAll('input[type="hidden"]').forEach(input => {
if (!input.name.includes('-id')) {
input.value = '';
}
});
newForm.querySelectorAll('input[type="number"]').forEach(input => {
input.value = '';
});
// Очищаем поле цены
const priceField = newForm.querySelector('[name$="-price"]');
if (priceField) {
priceField.value = '';
delete priceField.dataset.originalPrice;
}
newForm.querySelectorAll('input[type="checkbox"]').forEach(input => {
if (input.name.includes('DELETE')) {
input.checked = false;
}
});
// Скрываем индикаторы кастомной цены
const badge = newForm.querySelector('.custom-price-badge');
const priceInfo = newForm.querySelector('.original-price-info');
if (badge) badge.style.display = 'none';
if (priceInfo) priceInfo.style.display = 'none';
// Удаляем и пересоздаем Select2
const select2Element = newForm.querySelector('.select2-order-item');
const $select2Element = $(select2Element);
// Если Select2 уже был инициализирован, уничтожаем его
if ($select2Element.data('select2')) {
$select2Element.select2('destroy');
}
// Очищаем все опции, кроме первой пустой
select2Element.innerHTML = '<option value=""></option>';
select2Element.dataset.formIndex = formCount;
container.appendChild(newForm);
totalFormsInput.value = formCount + 1;
// Инициализируем Select2 для новой формы
initOrderItemSelect2(select2Element);
// Инициализируем отслеживание цены для новой формы
initPriceTracking(newForm);
});
// Перед отправкой: удалить пустые формы
document.getElementById('order-form').addEventListener('submit', function(e) {
const forms = container.querySelectorAll('.order-item-form');
forms.forEach(form => {
const productField = form.querySelector('[name$="-product"]');
const kitField = form.querySelector('[name$="-product_kit"]');
const deleteCheckbox = form.querySelector('[name$="-DELETE"]');
// Если оба поля пусты - пометить на удаление
if (!productField.value && !kitField.value && deleteCheckbox) {
deleteCheckbox.checked = true;
}
});
});
});
</script>
{% endblock %}