Реализован функционал создания временных комплектов на витрину из POS

- Добавлен API endpoint для создания временного комплекта из корзины
- Реализован endpoint получения списка активных витрин
- Создано модальное окно для настройки комплекта и выбора витрины
- JavaScript логика: валидация корзины, отправка данных, очистка после успеха
- Автоматическая генерация названия комплекта с датой и временем
- Агрегация дубликатов товаров в корзине перед созданием
- Резервирование компонентов на витрину через ShowcaseManager
- Расчёт и отображение итоговой цены комплекта
This commit is contained in:
2025-11-16 21:24:07 +03:00
parent 8f6acfb364
commit 156f646252
4 changed files with 403 additions and 3 deletions

View File

@@ -3,10 +3,15 @@ from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from products.models import Product, ProductCategory, ProductKit
from inventory.models import Showcase, Reservation
from django.db import transaction
from django.utils import timezone
from decimal import Decimal
import json
from products.models import Product, ProductCategory, ProductKit, KitItem
from inventory.models import Showcase, Reservation, Warehouse
from inventory.services import ShowcaseManager
@login_required
def pos_terminal(request):
@@ -97,3 +102,156 @@ def showcase_items_api(request):
'success': True,
'showcases': showcases_list
})
@login_required
@require_http_methods(["GET"])
def get_showcases_api(request):
"""
API endpoint для получения списка активных витрин.
Используется для выбора витрины при создании временного комплекта.
"""
showcases = Showcase.objects.filter(is_active=True).select_related('warehouse')
showcases_data = [{
'id': s.id,
'name': s.name,
'warehouse_name': s.warehouse.name,
'warehouse_id': s.warehouse.id
} for s in showcases]
return JsonResponse({
'success': True,
'showcases': showcases_data
})
@login_required
@require_http_methods(["POST"])
def create_temp_kit_to_showcase(request):
"""
API endpoint для создания временного комплекта из корзины POS
и резервирования его на витрину.
Ожидаемый payload:
{
"kit_name": "Название комплекта",
"showcase_id": 1,
"items": [
{"product_id": 1, "quantity": 2.0},
{"product_id": 3, "quantity": 1.0}
],
"price_adjustment_type": "none", // optional
"price_adjustment_value": 0 // optional
}
"""
try:
data = json.loads(request.body)
kit_name = data.get('kit_name', '').strip()
showcase_id = data.get('showcase_id')
items = data.get('items', [])
price_adjustment_type = data.get('price_adjustment_type', 'none')
price_adjustment_value = Decimal(str(data.get('price_adjustment_value', 0)))
# Валидация
if not kit_name:
return JsonResponse({
'success': False,
'error': 'Необходимо указать название комплекта'
}, status=400)
if not showcase_id:
return JsonResponse({
'success': False,
'error': 'Необходимо выбрать витрину'
}, status=400)
if not items or len(items) == 0:
return JsonResponse({
'success': False,
'error': 'Корзина пуста. Добавьте товары для создания комплекта'
}, status=400)
# Проверяем что витрина существует и активна
try:
showcase = Showcase.objects.select_related('warehouse').get(id=showcase_id, is_active=True)
except Showcase.DoesNotExist:
return JsonResponse({
'success': False,
'error': 'Витрина не найдена или неактивна'
}, status=404)
# Проверяем что все товары из корзины - это Product (не Kit)
product_ids = [item['product_id'] for item in items]
products = Product.objects.in_bulk(product_ids)
if len(products) != len(product_ids):
return JsonResponse({
'success': False,
'error': 'Некоторые товары не найдены'
}, status=400)
# Агрегируем дубликаты (если один товар добавлен несколько раз)
aggregated_items = {}
for item in items:
product_id = item['product_id']
quantity = Decimal(str(item['quantity']))
if product_id in aggregated_items:
aggregated_items[product_id] += quantity
else:
aggregated_items[product_id] = quantity
# Создаём временный комплект и резервируем на витрину
with transaction.atomic():
# 1. Создаём ProductKit (is_temporary=True)
kit = ProductKit.objects.create(
name=kit_name,
is_temporary=True,
status='active',
price_adjustment_type=price_adjustment_type,
price_adjustment_value=price_adjustment_value
)
# 2. Создаём KitItem для каждого товара из корзины
for product_id, quantity in aggregated_items.items():
KitItem.objects.create(
kit=kit,
product=products[product_id],
quantity=quantity
)
# 3. Пересчитываем цену комплекта
kit.recalculate_base_price()
# 4. Резервируем комплект на витрину
result = ShowcaseManager.reserve_kit_to_showcase(
product_kit=kit,
showcase=showcase,
quantity=1
)
if not result['success']:
# Откатываем транзакцию через raise
raise Exception(result['message'])
return JsonResponse({
'success': True,
'message': f'Временный комплект "{kit_name}" создан и зарезервирован на витрине "{showcase.name}"',
'kit_id': kit.id,
'kit_name': kit.name,
'kit_price': str(kit.actual_price),
'reservations_count': len(result['reservations'])
})
except json.JSONDecodeError:
return JsonResponse({
'success': False,
'error': 'Неверный формат данных'
}, status=400)
except Exception as e:
return JsonResponse({
'success': False,
'error': f'Ошибка при создании комплекта: {str(e)}'
}, status=500)