Files
octopus/myproject/pos/views.py
Andrey Smakotin 8f6acfb364 Добавлена функциональность витрин для POS: модели, сервисы, UI
- Создана модель Showcase (витрина) привязанная к складу
- Расширена Reservation для поддержки витринных резервов
- Добавлены поля в OrderItem для маркировки витринных продаж
- Реализован ShowcaseManager с методами резервирования, продажи и разбора
- Обновлён админ-интерфейс для управления витринами
- Добавлена кнопка Витрина в POS (категории) и API для просмотра
- Добавлена кнопка На витрину в панели действий POS
- Миграции готовы к применению
2025-11-16 21:12:22 +03:00

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
})