it_manager/locations: редактор шаблона этикеток, раздельная печать QR/EAN и карточка поставщика.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-07 16:40:48 +03:00
parent 82ad90c661
commit d54f6fbe42
18 changed files with 1192 additions and 66 deletions
+60 -5
View File
@@ -752,27 +752,30 @@ def equipment_bulk_create_view(request):
@login_required
def equipment_labels_view(request):
"""Печатная страница этикеток QR + EAN-13 для выбранного оборудования."""
"""Печатная страница этикеток по шаблону; codes=qr|ean|both."""
from django.shortcuts import render
from apps.it_manager.equipment_labels import label_payload_for_unit
from apps.it_manager.equipment_labels import (
get_default_template, label_payload_for_unit, parse_label_codes,
)
if not _is_it_staff(request.user):
return deny_section_access(request)
codes = parse_label_codes(request.GET.get('codes'))
raw_ids = request.GET.getlist('ids') or request.GET.get('ids', '').split(',')
ids = []
for part in raw_ids:
part = (part or '').strip()
if part.isdigit():
ids.append(int(part))
# порядок как в запросе, без дублей
seen, ordered = set(), []
for pk in ids:
if pk not in seen:
seen.add(pk)
ordered.append(pk)
template = get_default_template()
units_by_id = {
u.pk: u
for u in scoped_queryset(request.user, Equipment.objects.all())
@@ -785,9 +788,61 @@ def equipment_labels_view(request):
for pk in ordered:
unit = units_by_id.get(pk)
if unit is not None:
labels.append(label_payload_for_unit(unit))
labels.append(label_payload_for_unit(unit, codes=codes, template=template))
return render(request, 'pages/it-equipment-labels.html', {'labels': labels})
return render(request, 'pages/it-equipment-labels.html', {
'labels': labels,
'codes': codes,
'template_width_mm': template.width_mm,
'template_height_mm': template.height_mm,
})
@login_required
def equipment_label_template_view(request):
"""Редактор общего шаблона этикетки (GET страница / POST JSON)."""
import json
from django.http import JsonResponse
from django.shortcuts import render
from apps.it_manager.equipment_labels import get_default_template, normalize_layout
if not _is_it_staff(request.user):
return deny_section_access(request)
template = get_default_template()
if request.method == 'POST':
try:
payload = json.loads(request.body.decode('utf-8') or '{}')
except (json.JSONDecodeError, UnicodeDecodeError):
return JsonResponse({'ok': False, 'error': 'Некорректный JSON'}, status=400)
try:
width = float(payload.get('width_mm') or template.width_mm)
height = float(payload.get('height_mm') or template.height_mm)
except (TypeError, ValueError):
return JsonResponse({'ok': False, 'error': 'Некорректный размер'}, status=400)
if width < 20 or width > 200 or height < 15 or height > 200:
return JsonResponse({'ok': False, 'error': 'Размер вне диапазона 20–200 × 15–200 мм'}, status=400)
layout = normalize_layout(payload.get('layout'))
if not layout:
return JsonResponse({'ok': False, 'error': 'Добавьте хотя бы один блок'}, status=400)
template.width_mm = width
template.height_mm = height
template.layout = layout
template.updated_by = request.user
template.save()
return JsonResponse({'ok': True, 'updated_at': template.updated_at.isoformat()})
return render(request, 'pages/it-equipment-label-template.html', {
'template': template,
'template_json': json.dumps({
'width_mm': template.width_mm,
'height_mm': template.height_mm,
'layout': template.layout or [],
}, ensure_ascii=False),
})
@login_required