Before simplifying order creation and editing

This commit is contained in:
2025-11-28 23:11:34 +03:00
parent 94ddb0424b
commit f911a57640
12 changed files with 133 additions and 77 deletions

View File

@@ -126,7 +126,7 @@
<td>{{ transaction.description|default:"-" }}</td> <td>{{ transaction.description|default:"-" }}</td>
<td> <td>
{% if transaction.order %} {% if transaction.order %}
<a href="{% url 'orders:order-detail' transaction.order.pk %}" class="btn btn-sm btn-outline-primary"> <a href="{% url 'orders:order-detail' transaction.order.order_number %}" class="btn btn-sm btn-outline-primary">
#{{ transaction.order.order_number }} #{{ transaction.order.order_number }}
</a> </a>
{% else %} {% else %}
@@ -237,10 +237,10 @@
{% endif %} {% endif %}
</td> </td>
<td> <td>
<a href="{% url 'orders:order-detail' order.pk %}" class="btn btn-sm btn-outline-primary"> <a href="{% url 'orders:order-detail' order.order_number %}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i> <i class="bi bi-eye"></i>
</a> </a>
<a href="{% url 'orders:order-update' order.pk %}" class="btn btn-sm btn-outline-secondary"> <a href="{% url 'orders:order-update' order.order_number %}" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-pencil"></i> <i class="bi bi-pencil"></i>
</a> </a>
</td> </td>

View File

@@ -69,8 +69,8 @@
</td> </td>
<td> <td>
{% if r.order_item %} {% if r.order_item %}
<a href="{% url 'orders:order-detail' r.order_item.order.id %}" class="text-decoration-none"> <a href="{% url 'orders:order-detail' r.order_item.order.order_number %}" class="text-decoration-none">
<i class="bi bi-receipt me-1"></i>Заказ #{{ r.order_item.order.id }} <i class="bi bi-receipt me-1"></i>Заказ #{{ r.order_item.order.order_number }}
</a> </a>
{% else %} {% else %}
<span class="text-muted"></span> <span class="text-muted"></span>

View File

@@ -263,13 +263,15 @@ class OrderItemForm(forms.ModelForm):
self.fields['is_custom_price'].required = False self.fields['is_custom_price'].required = False
def clean_price(self): def clean_price(self):
"""Парсим цену с запятой или точкой""" """Парсим цену с запятой или точкой и округляем до 2 знаков"""
value = self.cleaned_data.get('price') value = self.cleaned_data.get('price')
if value in (None, ''): if value in (None, ''):
return None return None
value_str = str(value).strip().replace(',', '.') value_str = str(value).strip().replace(',', '.')
try: try:
return Decimal(value_str) price = Decimal(value_str)
# Округляем до 2 знаков после запятой
return price.quantize(Decimal('0.01'))
except Exception: except Exception:
raise forms.ValidationError('Введите число.') raise forms.ValidationError('Введите число.')

View File

@@ -248,6 +248,11 @@ class Order(models.Model):
def __str__(self): def __str__(self):
return f"Заказ #{self.order_number} - {self.customer}" return f"Заказ #{self.order_number} - {self.customer}"
def get_absolute_url(self):
"""Возвращает канонический URL для заказа"""
from django.urls import reverse
return reverse('orders:order-detail', kwargs={'order_number': self.order_number})
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
# Генерируем уникальный номер заказа при создании (начиная с 100 для 3-значного поиска) # Генерируем уникальный номер заказа при создании (начиная с 100 для 3-значного поиска)
if not self.order_number: if not self.order_number:

View File

@@ -172,9 +172,11 @@ class Payment(models.Model):
) )
# Нормализация переплаты: лишнее в кошелёк, amount_paid = total_amount # Нормализация переплаты: лишнее в кошелёк, amount_paid = total_amount
try: # ТОЛЬКО для новых платежей, чтобы избежать дублирования при обновлении
from customers.services.wallet_service import WalletService if is_new:
WalletService.add_overpayment(self.order, self.created_by) try:
except Exception: from customers.services.wallet_service import WalletService
# Продолжаем, даже если нормализация переплаты не удалась WalletService.add_overpayment(self.order, self.created_by)
pass except Exception:
# Продолжаем, даже если нормализация переплаты не удалась
pass

View File

@@ -11,14 +11,14 @@
// Конфигурация // Конфигурация
const CONFIG = { const CONFIG = {
AUTOSAVE_DELAY: 3000, // Задержка перед автосохранением (мс) AUTOSAVE_DELAY: 3000, // Задержка перед автосохранением (мс)
AUTOSAVE_URL_PATTERN: '/orders/{orderId}/autosave/', AUTOSAVE_URL_PATTERN: '/orders/{orderNumber}/autosave/',
STATUS_DISPLAY_DURATION: 5000, // Длительность показа статуса (мс) STATUS_DISPLAY_DURATION: 5000, // Длительность показа статуса (мс)
}; };
// Состояние модуля // Состояние модуля
let autosaveTimer = null; let autosaveTimer = null;
let isAutosaving = false; let isAutosaving = false;
let orderId = null; let orderNumber = null;
/** /**
* Инициализация модуля автосохранения * Инициализация модуля автосохранения
@@ -35,12 +35,12 @@
return; return;
} }
// Получаем ID заказа из URL // Получаем номер заказа из URL
const urlMatch = window.location.pathname.match(/\/orders\/(\d+)\/edit\//); const urlMatch = window.location.pathname.match(/\/orders\/(\d+)\/edit\//);
if (!urlMatch) { if (!urlMatch) {
return; return;
} }
orderId = urlMatch[1]; orderNumber = urlMatch[1];
// Инициализируем UI индикатора // Инициализируем UI индикатора
initStatusIndicator(); initStatusIndicator();
@@ -314,7 +314,7 @@
const formData = collectFormData(); const formData = collectFormData();
// Отправляем AJAX запрос // Отправляем AJAX запрос
const url = CONFIG.AUTOSAVE_URL_PATTERN.replace('{orderId}', orderId); const url = CONFIG.AUTOSAVE_URL_PATTERN.replace('{orderNumber}', orderNumber);
const response = await fetch(url, { const response = await fetch(url, {
method: 'POST', method: 'POST',
headers: { headers: {

View File

@@ -50,7 +50,7 @@
<form method="post" class="mt-4"> <form method="post" class="mt-4">
{% csrf_token %} {% csrf_token %}
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<a href="{% url 'orders:order-detail' order.pk %}" class="btn btn-secondary btn-lg"> <a href="{% url 'orders:order-detail' order.order_number %}" class="btn btn-secondary btn-lg">
<i class="bi bi-arrow-left"></i> Отмена <i class="bi bi-arrow-left"></i> Отмена
</a> </a>
<button type="submit" class="btn btn-danger btn-lg"> <button type="submit" class="btn btn-danger btn-lg">

View File

@@ -9,10 +9,10 @@
<h1>Заказ {{ order.order_number }}</h1> <h1>Заказ {{ order.order_number }}</h1>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<a href="{% url 'orders:order-update' order.pk %}" class="btn btn-primary"> <a href="{% url 'orders:order-update' order.order_number %}" class="btn btn-primary">
<i class="bi bi-pencil"></i> Редактировать <i class="bi bi-pencil"></i> Редактировать
</a> </a>
<a href="{% url 'orders:order-delete' order.pk %}" class="btn btn-danger"> <a href="{% url 'orders:order-delete' order.order_number %}" class="btn btn-danger">
<i class="bi bi-trash"></i> Удалить <i class="bi bi-trash"></i> Удалить
</a> </a>
<a href="{% url 'orders:order-list' %}" class="btn btn-secondary"> <a href="{% url 'orders:order-list' %}" class="btn btn-secondary">
@@ -250,7 +250,7 @@
<p class="text-muted small">Можно использовать для оплаты этого заказа</p> <p class="text-muted small">Можно использовать для оплаты этого заказа</p>
<!-- Кнопка "Применить максимум" --> <!-- Кнопка "Применить максимум" -->
<form method="post" action="{% url 'orders:apply-wallet' order.pk %}" class="mb-2"> <form method="post" action="{% url 'orders:apply-wallet' order.order_number %}" class="mb-2">
{% csrf_token %} {% 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 %}"> <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"> <button type="submit" class="btn btn-success w-100">
@@ -259,7 +259,7 @@
</form> </form>
<!-- Ручной ввод суммы --> <!-- Ручной ввод суммы -->
<form method="post" action="{% url 'orders:apply-wallet' order.pk %}"> <form method="post" action="{% url 'orders:apply-wallet' order.order_number %}">
{% csrf_token %} {% csrf_token %}
<div class="input-group"> <div class="input-group">
<input <input

View File

@@ -104,7 +104,7 @@
{% for order in page_obj %} {% for order in page_obj %}
<tr> <tr>
<td> <td>
<a href="{% url 'orders:order-detail' order.pk %}" class="text-decoration-none"> <a href="{% url 'orders:order-detail' order.order_number %}" class="text-decoration-none">
<strong>{{ order.order_number }}</strong> <strong>{{ order.order_number }}</strong>
</a> </a>
</td> </td>
@@ -130,7 +130,7 @@
{% endif %} {% endif %}
</td> </td>
<td> <td>
<div class="js-status-container" data-order-id="{{ order.pk }}"> <div class="js-status-container" data-order-number="{{ order.order_number }}">
<span class="badge badge-lg js-status-badge" style="{% if order.status %}background-color: {{ order.status.color }}; color: #fff;{% else %}background-color: #6c757d; color: #fff;{% endif %} cursor: pointer; font-size: 0.9rem; padding: 0.5rem 0.75rem;" title="Кликните для изменения"> <span class="badge badge-lg js-status-badge" style="{% if order.status %}background-color: {{ order.status.color }}; color: #fff;{% else %}background-color: #6c757d; color: #fff;{% endif %} cursor: pointer; font-size: 0.9rem; padding: 0.5rem 0.75rem;" title="Кликните для изменения">
{% if order.status %} {% if order.status %}
{{ order.status.label|default:order.status.name }} {{ order.status.label|default:order.status.name }}
@@ -165,12 +165,12 @@
{% endif %} {% endif %}
</td> </td>
<td> <td>
<a href="{% url 'orders:order-detail' order.pk %}" <a href="{% url 'orders:order-detail' order.order_number %}"
class="btn btn-sm btn-outline-primary" class="btn btn-sm btn-outline-primary"
title="Просмотр"> title="Просмотр">
<i class="bi bi-eye"></i> <i class="bi bi-eye"></i>
</a> </a>
<a href="{% url 'orders:order-update' order.pk %}" <a href="{% url 'orders:order-update' order.order_number %}"
class="btn btn-sm btn-outline-secondary" class="btn btn-sm btn-outline-secondary"
title="Редактировать"> title="Редактировать">
<i class="bi bi-pencil"></i> <i class="bi bi-pencil"></i>
@@ -239,9 +239,9 @@
(function() { (function() {
const csrfToken = '{{ csrf_token }}'; const csrfToken = '{{ csrf_token }}';
async function updateStatus(orderId, statusId) { async function updateStatus(orderNumber, statusId) {
const body = new URLSearchParams({ status_id: statusId }).toString(); const body = new URLSearchParams({ status_id: statusId }).toString();
const resp = await fetch(`/orders/api/${orderId}/set-status/`, { const resp = await fetch(`/orders/api/${orderNumber}/set-status/`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
@@ -255,7 +255,7 @@
document.querySelectorAll('.js-status-container').forEach(function(container) { document.querySelectorAll('.js-status-container').forEach(function(container) {
const badge = container.querySelector('.js-status-badge'); const badge = container.querySelector('.js-status-badge');
const select = container.querySelector('.js-status-select'); const select = container.querySelector('.js-status-select');
const orderId = container.dataset.orderId; const orderNumber = container.dataset.orderNumber;
// Click on badge: show select // Click on badge: show select
badge.addEventListener('click', function() { badge.addEventListener('click', function() {
@@ -278,7 +278,7 @@
select.disabled = true; select.disabled = true;
try { try {
const result = await updateStatus(orderId, statusId); const result = await updateStatus(orderNumber, statusId);
if (result.success) { if (result.success) {
// Update badge // Update badge
const newColor = selectedOption.dataset.color || '#6c757d'; const newColor = selectedOption.dataset.color || '#6c757d';

View File

@@ -7,20 +7,20 @@ app_name = 'orders'
urlpatterns = [ urlpatterns = [
path('', views.order_list, name='order-list'), path('', views.order_list, name='order-list'),
path('create/', views.order_create, name='order-create'), path('create/', views.order_create, name='order-create'),
path('<int:pk>/', views.order_detail, name='order-detail'), path('<int:order_number>/', views.order_detail, name='order-detail'),
path('<int:pk>/edit/', views.order_update, name='order-update'), path('<int:order_number>/edit/', views.order_update, name='order-update'),
path('<int:pk>/delete/', views.order_delete, name='order-delete'), path('<int:order_number>/delete/', views.order_delete, name='order-delete'),
# AJAX endpoints # AJAX endpoints
path('<int:pk>/autosave/', views.autosave_draft_order, name='order-autosave'), path('<int:order_number>/autosave/', views.autosave_draft_order, name='order-autosave'),
path('create-draft/', views.create_draft_from_form, name='order-create-draft'), path('create-draft/', views.create_draft_from_form, name='order-create-draft'),
path('api/customer-address-history/', views.get_customer_address_history, name='api-customer-address-history'), path('api/customer-address-history/', views.get_customer_address_history, name='api-customer-address-history'),
# Wallet payment # Wallet payment
path('<int:pk>/apply-wallet/', views.apply_wallet_payment, name='apply-wallet'), path('<int:order_number>/apply-wallet/', views.apply_wallet_payment, name='apply-wallet'),
# AJAX status update # AJAX status update
path('api/<int:pk>/set-status/', views.set_order_status, name='api-set-order-status'), path('api/<int:order_number>/set-status/', views.set_order_status, name='api-set-order-status'),
# Order Status Management URLs # Order Status Management URLs
path('statuses/', views.order_status_list, name='status_list'), path('statuses/', views.order_status_list, name='status_list'),

View File

@@ -46,12 +46,12 @@ def order_list(request):
return render(request, 'orders/order_list.html', context) return render(request, 'orders/order_list.html', context)
def order_detail(request, pk): def order_detail(request, order_number):
"""Детальная информация о заказе""" """Детальная информация о заказе"""
order = get_object_or_404( order = get_object_or_404(
Order.objects.select_related('customer', 'delivery_address', 'pickup_warehouse', 'modified_by') Order.objects.select_related('customer', 'delivery_address', 'pickup_warehouse', 'modified_by')
.prefetch_related('items__product', 'items__product_kit', 'payments__created_by'), .prefetch_related('items__product', 'items__product_kit', 'payments__created_by'),
pk=pk order_number=order_number
) )
context = { context = {
@@ -104,7 +104,7 @@ def order_create(request):
messages.success(request, f'Черновик #{order.order_number} успешно создан!') messages.success(request, f'Черновик #{order.order_number} успешно создан!')
else: else:
messages.success(request, f'Заказ #{order.order_number} успешно создан!') messages.success(request, f'Заказ #{order.order_number} успешно создан!')
return redirect('orders:order-detail', pk=order.pk) return redirect('orders:order-detail', order_number=order.order_number)
else: else:
messages.error(request, 'Пожалуйста, исправьте ошибки в форме.') messages.error(request, 'Пожалуйста, исправьте ошибки в форме.')
else: else:
@@ -136,9 +136,9 @@ def order_create(request):
return render(request, 'orders/order_form.html', context) return render(request, 'orders/order_form.html', context)
def order_update(request, pk): def order_update(request, order_number):
"""Редактирование заказа""" """Редактирование заказа"""
order = get_object_or_404(Order, pk=pk) order = get_object_or_404(Order, order_number=order_number)
if request.method == 'POST': if request.method == 'POST':
form = OrderForm(request.POST, instance=order) form = OrderForm(request.POST, instance=order)
@@ -153,7 +153,7 @@ def order_update(request, pk):
try: try:
order = DraftOrderService.finalize_draft(order.pk, request.user) order = DraftOrderService.finalize_draft(order.pk, request.user)
messages.success(request, f'Черновик #{order.order_number} успешно завершен и переведен в статус "Новый"!') messages.success(request, f'Черновик #{order.order_number} успешно завершен и переведен в статус "Новый"!')
return redirect('orders:order-detail', pk=order.pk) return redirect('orders:order-detail', order_number=order.order_number)
except ValidationError as e: except ValidationError as e:
messages.error(request, f'Ошибка финализации: {str(e)}') messages.error(request, f'Ошибка финализации: {str(e)}')
form = OrderForm(instance=order) form = OrderForm(instance=order)
@@ -200,7 +200,7 @@ def order_update(request, pk):
messages.success(request, f'Черновик #{order.order_number} успешно обновлен!') messages.success(request, f'Черновик #{order.order_number} успешно обновлен!')
else: else:
messages.success(request, f'Заказ #{order.order_number} успешно обновлен!') messages.success(request, f'Заказ #{order.order_number} успешно обновлен!')
return redirect('orders:order-detail', pk=order.pk) return redirect('orders:order-detail', order_number=order.order_number)
else: else:
# Логируем ошибки для отладки # Логируем ошибки для отладки
print("\n=== ОШИБКИ ВАЛИДАЦИИ ФОРМЫ ===") print("\n=== ОШИБКИ ВАЛИДАЦИИ ФОРМЫ ===")
@@ -235,9 +235,9 @@ def order_update(request, pk):
return render(request, 'orders/order_form.html', context) return render(request, 'orders/order_form.html', context)
def order_delete(request, pk): def order_delete(request, order_number):
"""Удаление заказа с подтверждением""" """Удаление заказа с подтверждением"""
order = get_object_or_404(Order, pk=pk) order = get_object_or_404(Order, order_number=order_number)
if request.method == 'POST': if request.method == 'POST':
order_number = order.order_number order_number = order.order_number
@@ -256,7 +256,7 @@ def order_delete(request, pk):
@require_http_methods(["POST"]) @require_http_methods(["POST"])
@login_required @login_required
def autosave_draft_order(request, pk): def autosave_draft_order(request, order_number):
""" """
AJAX endpoint для автосохранения черновика заказа. AJAX endpoint для автосохранения черновика заказа.
@@ -289,46 +289,93 @@ def autosave_draft_order(request, pk):
# Проверяем существование заказа # Проверяем существование заказа
try: try:
order = Order.objects.get(pk=pk) order = Order.objects.get(order_number=order_number)
except Order.DoesNotExist: except Order.DoesNotExist:
return JsonResponse({ return JsonResponse({
'success': False, 'success': False,
'error': 'Заказ не найден' 'error': 'Заказ не найден'
}, status=404) }, status=404)
# Используем DraftOrderService для обновления # Обновляем основные поля заказа из DraftOrderService (БЕЗ товаров)
# Товары обрабатываем отдельно ниже
order_fields_only = {k: v for k, v in data.items() if k not in ['items', 'payments']}
order = DraftOrderService.update_draft( order = DraftOrderService.update_draft(
order_id=pk, order_id=order.pk,
user=request.user, user=request.user,
data=data data=order_fields_only
) )
# Обрабатываем позиции заказа, если они переданы # Обрабатываем позиции заказа, если они переданы
if 'items' in data: if 'items' in data:
# Удаляем существующие позиции from decimal import Decimal, InvalidOperation
order.items.all().delete()
# Создаем новые позиции # Получаем ID товаров, которые нужно удалить
deleted_item_ids = data.get('deleted_item_ids', [])
if deleted_item_ids:
order.items.filter(pk__in=deleted_item_ids).delete()
# Обрабатываем каждый товар
for item_data in data['items']: for item_data in data['items']:
item_id = item_data.get('id') # ID существующего товара (если есть)
product_id = item_data.get('product_id') product_id = item_data.get('product_id')
product_kit_id = item_data.get('product_kit_id') product_kit_id = item_data.get('product_kit_id')
quantity = item_data.get('quantity') quantity = item_data.get('quantity')
price = item_data.get('price') price_raw = item_data.get('price')
if product_id: # Преобразуем цену
DraftOrderService.add_item_to_draft( try:
order_id=order.pk, price = Decimal(str(price_raw).replace(',', '.')) if price_raw else None
product_id=product_id, except (ValueError, InvalidOperation):
quantity=quantity, price = None
price=price
) # Если есть ID - обновляем существующий товар
elif product_kit_id: if item_id:
DraftOrderService.add_item_to_draft( try:
order_id=order.pk, item = order.items.get(pk=item_id)
product_kit_id=product_kit_id, # Обновляем поля
quantity=quantity, if product_id:
price=price from products.models import Product
) item.product = Product.objects.get(pk=product_id)
item.product_kit = None
elif product_kit_id:
from products.models import ProductKit
item.product_kit = ProductKit.objects.get(pk=product_kit_id)
item.product = None
if quantity:
item.quantity = quantity
if price is not None:
item.price = price
item.save()
except OrderItem.DoesNotExist:
# Если товар не найден, создаем новый
item_id = None
# Если нет ID - создаем новый товар
if not item_id:
if product_id:
DraftOrderService.add_item_to_draft(
order_id=order.pk,
product_id=product_id,
quantity=quantity,
price=price
)
elif product_kit_id:
DraftOrderService.add_item_to_draft(
order_id=order.pk,
product_kit_id=product_kit_id,
quantity=quantity,
price=price
)
# НЕ ОБРАБАТЫВАЕМ ПЛАТЕЖИ В АВТОСОХРАНЕНИИ
# Платежи обрабатываются только при ручном сохранении формы
# Пересчитываем итоговую сумму заказа и обновляем статус оплаты
order.calculate_total()
order.update_payment_status()
order.save()
return JsonResponse({ return JsonResponse({
'success': True, 'success': True,
@@ -432,7 +479,7 @@ def create_draft_from_form(request):
'success': True, 'success': True,
'order_id': order.pk, 'order_id': order.pk,
'order_number': order.order_number, 'order_number': order.order_number,
'redirect_url': f'/orders/{order.pk}/edit/' 'redirect_url': f'/orders/{order.order_number}/edit/'
}) })
except ValidationError as e: except ValidationError as e:
@@ -637,15 +684,15 @@ def order_status_delete(request, pk):
# === КОШЕЛЁК КЛИЕНТА === # === КОШЕЛЁК КЛИЕНТА ===
@login_required @login_required
def apply_wallet_payment(request, pk): def apply_wallet_payment(request, order_number):
""" """
Применение оплаты из кошелька клиента к заказу. Применение оплаты из кошелька клиента к заказу.
Вызывается через POST-запрос с суммой для списания. Вызывается через POST-запрос с суммой для списания.
""" """
if request.method != 'POST': if request.method != 'POST':
return redirect('orders:order-detail', pk=pk) return redirect('orders:order-detail', order_number=order_number)
order = get_object_or_404(Order, pk=pk) order = get_object_or_404(Order, order_number=order_number)
# Получаем запрашиваемую сумму из формы # Получаем запрашиваемую сумму из формы
try: try:
@@ -675,19 +722,19 @@ def apply_wallet_payment(request, pk):
except Exception as e: except Exception as e:
messages.error(request, f'Ошибка при оплате из кошелька: {str(e)}') messages.error(request, f'Ошибка при оплате из кошелька: {str(e)}')
return redirect('orders:order-detail', pk=pk) return redirect('orders:order-detail', order_number=order.order_number)
@require_http_methods(["POST"]) @require_http_methods(["POST"])
@login_required @login_required
def set_order_status(request, pk): def set_order_status(request, order_number):
""" """
Update order status via AJAX. Update order status via AJAX.
Accepts POST with 'status_id' (can be empty to clear). Accepts POST with 'status_id' (can be empty to clear).
Returns JSON with the resulting status info. Returns JSON with the resulting status info.
""" """
try: try:
order = get_object_or_404(Order, pk=pk) order = get_object_or_404(Order, order_number=order_number)
status_id = request.POST.get('status_id', '').strip() status_id = request.POST.get('status_id', '').strip()
# Allow clearing status if empty # Allow clearing status if empty

View File

@@ -82,7 +82,7 @@
</div> </div>
<div class="d-grid gap-2 d-md-flex justify-content-md-between"> <div class="d-grid gap-2 d-md-flex justify-content-md-between">
<a href="{% url 'orders:order-detail' kit.order.pk %}" class="btn btn-secondary"> <a href="{% url 'orders:order-detail' kit.order.order_number %}" class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> Отмена <i class="bi bi-arrow-left"></i> Отмена
</a> </a>
<button type="submit" class="btn btn-success"> <button type="submit" class="btn btn-success">