Добавлена возможность выбора анонимного системного клиента в форме заказа

- Убрана фильтрация системного клиента из результатов поиска (api_search_customers)
- Добавлен флаг is_system_customer в результаты API поиска
- Создан новый API endpoint api_get_system_customer для быстрого получения системного клиента
- Добавлена кнопка 'Аноним' для быстрого выбора системного клиента
- Системный клиент выделяется жёлтым цветом и иконкой инкогнито в выпадающем списке
- Улучшена компактность результатов поиска (уменьшен шрифт до 13px)
- Изменены пропорции полей: клиент 9 колонок, статус 3 колонки (было 6:6)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-15 12:54:56 +03:00
parent c7e03d258b
commit 2ef537fff6
4 changed files with 218 additions and 35 deletions

View File

@@ -45,6 +45,22 @@
font-size: 1.1em;
}
/* Стили для системного клиента */
.system-customer-option {
background-color: #fff3cd;
padding: 8px 12px;
border-radius: 4px;
border-left: 3px solid #ffc107;
}
.system-customer-option:hover {
background-color: #ffe69c;
}
.system-customer-option i {
margin-right: 5px;
}
/* Select2 dropdown styling */
.select2-results__option.customer-option-item {
padding: 8px 8px;
@@ -55,6 +71,50 @@
border-bottom: none;
}
/* Компактные стили для результатов поиска клиентов */
.customer-option {
padding: 4px 0 !important;
font-size: 13px;
line-height: 1.3;
}
.customer-option small {
font-size: 11px;
line-height: 1.2;
}
.customer-create-option {
padding: 6px 10px !important;
font-size: 13px;
}
.system-customer-option {
padding: 6px 10px !important;
font-size: 13px;
line-height: 1.3;
}
.system-customer-option small {
font-size: 11px;
}
/* Input group с Select2 и кнопкой системного клиента */
.customer-select-wrapper {
display: flex;
flex-wrap: nowrap;
gap: 0;
}
.customer-select-wrapper .select2-container {
flex: 1;
min-width: 0;
}
.customer-select-wrapper .btn {
flex-shrink: 0;
border-radius: 0 4px 4px 0;
}
/* ИСПРАВЛЕНИЕ: Убедимся что Select2 dropdown видим и поверх всех элементов */
.select2-container--open {
z-index: 9999 !important;
@@ -85,10 +145,11 @@
.select2-results {
max-height: 400px;
overflow-y: auto;
font-size: 13px;
}
.select2-results__option {
padding: 8px 8px;
padding: 6px 8px;
color: #212529;
}
@@ -139,48 +200,54 @@
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="col-md-9">
<div class="mb-3">
<label for="{{ form.customer.id_for_label }}" class="form-label">
Клиент <span class="text-danger">*</span>
</label>
{% if preselected_customer %}
<select name="customer"
class="form-select customer-select2-auto"
id="id_customer"
data-ajax-url="{% url 'customers:api-search-customers' %}"
data-create-url="{% url 'customers:api-create-customer' %}"
data-modal-id="createCustomerModal">
<option value="{{ preselected_customer.pk }}" selected
data-name="{{ preselected_customer.name }}"
data-phone="{{ preselected_customer.phone|default:'' }}"
data-email="{{ preselected_customer.email|default:'' }}">
{{ preselected_customer.name }}{% if preselected_customer.phone %} ({{ preselected_customer.phone }}){% endif %}
</option>
</select>
{% else %}
<select name="customer"
class="form-select customer-select2-auto"
id="id_customer"
data-ajax-url="{% url 'customers:api-search-customers' %}"
data-create-url="{% url 'customers:api-create-customer' %}"
data-modal-id="createCustomerModal">
{% if form.customer.value %}
<option value="{{ form.customer.value }}" selected
data-name="{{ form.instance.customer.name }}"
data-phone="{{ form.instance.customer.phone|default:'' }}"
data-email="{{ form.instance.customer.email|default:'' }}">
{{ form.instance.customer.name }}{% if form.instance.customer.phone %} ({{ form.instance.customer.phone }}){% endif %}
<div class="customer-select-wrapper">
{% if preselected_customer %}
<select name="customer"
class="form-select customer-select2-auto"
id="id_customer"
data-ajax-url="{% url 'customers:api-search-customers' %}"
data-create-url="{% url 'customers:api-create-customer' %}"
data-modal-id="createCustomerModal">
<option value="{{ preselected_customer.pk }}" selected
data-name="{{ preselected_customer.name }}"
data-phone="{{ preselected_customer.phone|default:'' }}"
data-email="{{ preselected_customer.email|default:'' }}">
{{ preselected_customer.name }}{% if preselected_customer.phone %} ({{ preselected_customer.phone }}){% endif %}
</option>
{% endif %}
</select>
{% endif %}
</select>
{% else %}
<select name="customer"
class="form-select customer-select2-auto"
id="id_customer"
data-ajax-url="{% url 'customers:api-search-customers' %}"
data-create-url="{% url 'customers:api-create-customer' %}"
data-modal-id="createCustomerModal">
{% if form.customer.value %}
<option value="{{ form.customer.value }}" selected
data-name="{{ form.instance.customer.name }}"
data-phone="{{ form.instance.customer.phone|default:'' }}"
data-email="{{ form.instance.customer.email|default:'' }}">
{{ form.instance.customer.name }}{% if form.instance.customer.phone %} ({{ form.instance.customer.phone }}){% endif %}
</option>
{% endif %}
</select>
{% endif %}
<button type="button" class="btn btn-outline-warning" id="select-system-customer-btn"
title="Выбрать анонимного покупателя" data-system-url="{% url 'customers:api-get-system-customer' %}">
<i class="bi bi-incognito"></i> Аноним
</button>
</div>
{% if form.customer.errors %}
<div class="text-danger">{{ form.customer.errors }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="col-md-3">
<div class="mb-3">
<label for="{{ form.status.id_for_label }}" class="form-label">
Статус <span class="text-danger">*</span>
@@ -1015,6 +1082,79 @@ document.addEventListener('DOMContentLoaded', function() {
<!-- Customer Select2 Widget -->
<script src="{% static 'orders/js/customer_select2.js' %}" defer></script>
<!-- System Customer Button Script -->
<script>
(function() {
'use strict';
function initSystemCustomerButton() {
const button = document.getElementById('select-system-customer-btn');
if (!button) return;
const systemUrl = button.dataset.systemUrl;
const customerSelect = document.getElementById('id_customer');
if (!customerSelect) return;
button.addEventListener('click', function() {
// Показываем индикатор загрузки
const originalHTML = button.innerHTML;
button.disabled = true;
button.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Загрузка...';
fetch(systemUrl)
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.success && data.customer) {
// Обновляем Select2
if (typeof $ !== 'undefined') {
const $select = $(customerSelect);
// Удаляем текущую опцию, если есть
$select.empty();
// Добавляем нового клиента
const newOption = new Option(
data.customer.name,
data.customer.id,
true,
true
);
// Добавляем data-атрибуты
$(newOption).attr({
'data-name': data.customer.name,
'data-phone': data.customer.phone,
'data-email': data.customer.email,
'data-is-system-customer': 'true'
});
$select.append(newOption).trigger('change');
}
// Показываем уведомление
if (window.showNotification) {
window.showNotification('Выбран анонимный покупатель', 'success');
}
}
})
.catch(function(error) {
console.error('Error loading system customer:', error);
if (window.showNotification) {
window.showNotification('Ошибка при загрузке системного клиента', 'error');
}
})
.finally(function() {
button.disabled = false;
button.innerHTML = originalHTML;
});
});
}
// Инициализация при загрузке DOM
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSystemCustomerButton);
} else {
initSystemCustomerButton();
}
})();
</script>
<script>
// Инициализация Select2 для остальных полей (после jQuery загружен)
if (typeof $ !== 'undefined') {