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

@@ -107,6 +107,24 @@ def order_create(request):
initial_data = {} initial_data = {}
preselected_customer = None preselected_customer = None
customer_id = request.GET.get('customer') customer_id = request.GET.get('customer')
# Проверяем, есть ли черновик из POS
draft_token = request.GET.get('draft')
draft_items = []
if draft_token:
from django.core.cache import cache
cache_key = f'pos_draft:{draft_token}'
draft_data = cache.get(cache_key)
if draft_data:
# Загружаем клиента из черновика
customer_id = draft_data.get('customer_id')
draft_items = draft_data.get('items', [])
# Удаляем черновик из кэша (одноразовый токен)
cache.delete(cache_key)
if customer_id: if customer_id:
try: try:
from customers.models import Customer from customers.models import Customer
@@ -116,6 +134,36 @@ def order_create(request):
pass pass
form = OrderForm(initial=initial_data) form = OrderForm(initial=initial_data)
# Создаем formset с предзаполненными товарами из черновика
if draft_items:
from products.models import Product, ProductKit
initial_formset_data = []
for item in draft_items:
item_data = {
'quantity': item['quantity'],
'price': item['price'],
'is_custom_price': False,
}
if item['type'] == 'product':
try:
product = Product.objects.get(id=item['id'])
item_data['product'] = product.id
initial_formset_data.append(item_data)
except Product.DoesNotExist:
pass
elif item['type'] in ['kit', 'showcase_kit']:
try:
kit = ProductKit.objects.get(id=item['id'])
item_data['product_kit'] = kit.id
initial_formset_data.append(item_data)
except ProductKit.DoesNotExist:
pass
formset = OrderItemFormSet(initial=initial_formset_data)
else:
formset = OrderItemFormSet() formset = OrderItemFormSet()
context = { context = {

View File

@@ -1984,3 +1984,61 @@ setupInfiniteScroll(); // Установка infinite scroll
// Установить фокус на строку поиска // Установить фокус на строку поиска
document.getElementById('searchInput').focus(); 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'), path('api/showcase-kits/', views.get_showcase_kits_api, name='showcase-kits-api'),
# Добавить витринный комплект в корзину с блокировкой [POST] # Добавить витринный комплект в корзину с блокировкой [POST]
path('api/showcase-kits/<int:kit_id>/add-to-cart/', views.add_showcase_kit_to_cart, name='add-showcase-kit-to-cart'), 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] # Снять блокировку витринного комплекта при удалении из корзины [POST]
path('api/showcase-kits/<int:kit_id>/remove-from-cart/', views.remove_showcase_kit_from_cart, name='remove-showcase-kit-from-cart'), path('api/showcase-kits/<int:kit_id>/remove-from-cart/', views.remove_showcase_kit_from_cart, name='remove-showcase-kit-from-cart'),
# Получить детали комплекта для редактирования [GET] # Получить детали комплекта для редактирования [GET]

View File

@@ -1416,3 +1416,59 @@ def pos_checkout(request):
except Exception as e: except Exception as e:
logger.error(f'Ошибка при проведении продажи POS: {str(e)}', exc_info=True) logger.error(f'Ошибка при проведении продажи POS: {str(e)}', exc_info=True)
return JsonResponse({'success': False, 'error': f'Ошибка: {str(e)}'}, status=500) 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)