- Создана модель Showcase (витрина) привязанная к складу - Расширена Reservation для поддержки витринных резервов - Добавлены поля в OrderItem для маркировки витринных продаж - Реализован ShowcaseManager с методами резервирования, продажи и разбора - Обновлён админ-интерфейс для управления витринами - Добавлена кнопка Витрина в POS (категории) и API для просмотра - Добавлена кнопка На витрину в панели действий POS - Миграции готовы к применению
100 lines
3.8 KiB
Python
100 lines
3.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
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
|
|
import json
|
|
|
|
|
|
@login_required
|
|
def pos_terminal(request):
|
|
"""
|
|
Tablet-friendly POS screen prototype.
|
|
Shows categories and all items (products + kits) for quick tap-to-add.
|
|
"""
|
|
categories_qs = ProductCategory.objects.filter(is_active=True)
|
|
# Показываем все товары, не только in_stock
|
|
products_qs = Product.objects.all().prefetch_related('categories', 'photos')
|
|
# Показываем все комплекты (кроме временных)
|
|
kits_qs = ProductKit.objects.filter(is_temporary=False).prefetch_related('categories', 'photos')
|
|
|
|
categories = [{'id': c.id, 'name': c.name} for c in categories_qs]
|
|
|
|
# Сериализация товаров
|
|
products = [{
|
|
'id': p.id,
|
|
'name': p.name,
|
|
'price': str(p.actual_price),
|
|
'category_ids': [c.id for c in p.categories.all()],
|
|
'in_stock': p.in_stock,
|
|
'sku': p.sku or '',
|
|
'image': p.photos.first().get_thumbnail_url() if p.photos.exists() else None,
|
|
'type': 'product'
|
|
} for p in products_qs]
|
|
|
|
# Сериализация комплектов
|
|
kits = [{
|
|
'id': k.id,
|
|
'name': k.name,
|
|
'price': str(k.actual_price),
|
|
'category_ids': [c.id for c in k.categories.all()],
|
|
'in_stock': False, # Комплекты всегда "Под заказ" (пока не интегрируем проверку наличия)
|
|
'sku': k.sku or '',
|
|
'image': k.photos.first().get_thumbnail_url() if k.photos.exists() else None,
|
|
'type': 'kit'
|
|
} for k in kits_qs]
|
|
|
|
# Объединяем все позиции
|
|
all_items = products + kits
|
|
|
|
context = {
|
|
'categories_json': json.dumps(categories),
|
|
'items_json': json.dumps(all_items), # Единый массив товаров и комплектов
|
|
'title': 'POS Terminal',
|
|
}
|
|
return render(request, 'pos/terminal.html', context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def showcase_items_api(request):
|
|
"""
|
|
API endpoint для получения витринных букетов.
|
|
Возвращает комплекты, зарезервированные на активных витринах.
|
|
"""
|
|
# Получаем все активные резервы на витринах
|
|
showcase_reservations = Reservation.objects.filter(
|
|
showcase__isnull=False,
|
|
showcase__is_active=True,
|
|
status='reserved'
|
|
).select_related('showcase', 'product').prefetch_related('product__photos')
|
|
|
|
# Группируем по витринам
|
|
showcases_dict = {}
|
|
for res in showcase_reservations:
|
|
showcase_id = res.showcase.id
|
|
if showcase_id not in showcases_dict:
|
|
showcases_dict[showcase_id] = {
|
|
'id': showcase_id,
|
|
'name': res.showcase.name,
|
|
'warehouse': res.showcase.warehouse.name,
|
|
'items': []
|
|
}
|
|
|
|
# Добавляем товар в список
|
|
showcases_dict[showcase_id]['items'].append({
|
|
'product_id': res.product.id,
|
|
'product_name': res.product.name,
|
|
'quantity': str(res.quantity),
|
|
'image': res.product.photos.first().get_thumbnail_url() if res.product.photos.exists() else None,
|
|
})
|
|
|
|
showcases_list = list(showcases_dict.values())
|
|
|
|
return JsonResponse({
|
|
'success': True,
|
|
'showcases': showcases_list
|
|
})
|