POS deferred order feature

This commit is contained in:
2025-12-08 18:56:14 +03:00
parent a244d82e49
commit 6c19c9e093
4 changed files with 165 additions and 1 deletions

View File

@@ -1984,3 +1984,61 @@ setupInfiniteScroll(); // Установка infinite scroll
// Установить фокус на строку поиска
document.getElementById('searchInput').focus();
// ===== ОТЛОЖЕННЫЙ ЗАКАЗ =====
/**
* Открывает страницу создания заказа с предзаполненными товарами и клиентом
*/
async function createDeferredOrder() {
// Проверяем, что корзина не пуста
if (cart.size === 0) {
alert('Корзина пуста! Добавьте товары в корзину.');
return;
}
try {
// Собираем данные для черновика
const items = Array.from(cart.values()).map(item => ({
type: item.type,
id: item.id,
quantity: item.qty,
price: item.price
}));
const customer = selectedCustomer || SYSTEM_CUSTOMER;
const draftData = {
customer_id: customer.id,
items: items
};
// Отправляем на сервер
const response = await fetch('/pos/api/create-draft/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCsrfToken()
},
body: JSON.stringify(draftData)
});
const result = await response.json();
if (result.success) {
// Открываем в новой вкладке
window.open(`/orders/create/?draft=${result.token}`, '_blank');
} else {
alert(`Ошибка: ${result.error}`);
}
} catch (error) {
console.error('Ошибка при создании отложенного заказа:', error);
alert('Произошла ошибка при создании черновика заказа');
}
}
// Обработчик кнопки "ОТЛОЖЕННЫЙ заказ"
const scheduleLaterBtn = document.getElementById('scheduleLater');
if (scheduleLaterBtn) {
scheduleLaterBtn.addEventListener('click', createDeferredOrder);
}

View File

@@ -21,6 +21,8 @@ urlpatterns = [
path('api/showcase-kits/', views.get_showcase_kits_api, name='showcase-kits-api'),
# Добавить витринный комплект в корзину с блокировкой [POST]
path('api/showcase-kits/<int:kit_id>/add-to-cart/', views.add_showcase_kit_to_cart, name='add-showcase-kit-to-cart'),
# Сохранить черновик заказа для передачи в orders/create/ [POST]
path('api/create-draft/', views.create_order_draft, name='create-order-draft'),
# Снять блокировку витринного комплекта при удалении из корзины [POST]
path('api/showcase-kits/<int:kit_id>/remove-from-cart/', views.remove_showcase_kit_from_cart, name='remove-showcase-kit-from-cart'),
# Получить детали комплекта для редактирования [GET]

View File

@@ -1416,3 +1416,59 @@ def pos_checkout(request):
except Exception as e:
logger.error(f'Ошибка при проведении продажи POS: {str(e)}', exc_info=True)
return JsonResponse({'success': False, 'error': f'Ошибка: {str(e)}'}, status=500)
@login_required
@require_http_methods(["POST"])
def create_order_draft(request):
"""
Создает черновик заказа из корзины POS и сохраняет в Redis.
Возвращает токен для передачи в orders/create/.
Payload (JSON):
{
"customer_id": int,
"items": [
{"type": "product"|"kit"|"showcase_kit", "id": int, "quantity": float, "price": float},
...
]
}
Response:
{
"success": true,
"token": "abc123..."
}
"""
from django.core.cache import cache
import secrets
try:
data = json.loads(request.body)
customer_id = data.get('customer_id')
items = data.get('items', [])
if not items:
return JsonResponse({'success': False, 'error': 'Корзина пуста'}, status=400)
# Генерируем уникальный токен
token = secrets.token_urlsafe(16)
# Сохраняем в Redis с TTL 1 час
cache_key = f'pos_draft:{token}'
draft_data = {
'customer_id': customer_id,
'items': items,
}
cache.set(cache_key, draft_data, timeout=3600) # 1 час
return JsonResponse({
'success': True,
'token': token
})
except json.JSONDecodeError:
return JsonResponse({'success': False, 'error': 'Неверный формат JSON'}, status=400)
except Exception as e:
logger.error(f'Ошибка при создании черновика заказа: {str(e)}', exc_info=True)
return JsonResponse({'success': False, 'error': f'Ошибка: {str(e)}'}, status=500)