baseline: 批次A-D 成果 + membership 半成品(测试红)

This commit is contained in:
agent
2026-09-11 23:11:35 +08:00
commit b3f3095d53
311 changed files with 40540 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
"""打印中心 async ViewSets。
- PrintTemplateViewSet:模板 CRUD
- PrintSettingsViewSet:抬头读取/更新(单例)
- render_document_view:渲染整页打印 HTML(前端 axios 取回后 window.print())
"""
from asgiref.sync import sync_to_async
from adrf.decorators import api_view
from rest_framework import status
from rest_framework.response import Response
from rest_framework.exceptions import ValidationError, NotFound
from apps.core.viewset import BaseTenantViewSet
from .models import PrintSettings, PrintTemplate
from .serializers import PrintSettingsSerializer, PrintTemplateSerializer
from . import services as printing_services
class PrintTemplateViewSet(BaseTenantViewSet):
model = PrintTemplate
serializer_class = PrintTemplateSerializer
search_fields = ["code", "name", "doc_type"]
@api_view(["GET", "PUT", "PATCH"])
async def print_settings_detail(request):
"""打印抬头:租户单例。GET 读取 / PUT(整更) / PATCH(部分更)。"""
from apps.core.viewset import resolve_tenant
def _resolve():
return resolve_tenant(request.META.get("HTTP_X_TENANT_ID", ""))
tenant = await sync_to_async(_resolve)()
if tenant is None:
raise ValidationError({"tenant": "无法识别租户"})
obj = await sync_to_async(printing_services.ensure_settings)(tenant)
if request.method == "GET":
serializer = PrintSettingsSerializer(obj)
data = await serializer.adata if hasattr(serializer, "adata") else serializer.data
return Response(serializer.data)
partial = request.method == "PATCH"
serializer = PrintSettingsSerializer(obj, data=request.data, partial=partial)
await sync_to_async(serializer.is_valid)(raise_exception=True)
await sync_to_async(serializer.save)(
updated_by=request.user if request.user.is_authenticated else None
)
return Response(serializer.data)
@api_view(["GET"])
async def render_document_view(request, doc_type, document_id):
"""GET /api/v1/printing/render/<doc_type>/<id>/?template=code&autoprint=0
返回整页 HTML(Content-Type: text/html)。鉴权走 JWT + 租户中间件。
"""
from django.http import HttpResponse
from apps.core.viewset import resolve_tenant
if doc_type not in printing_services.DOC_CONTEXT_BUILDERS:
raise ValidationError({"doc_type": f"不支持的文档类型 {doc_type}"})
def _resolve():
code = request.META.get("HTTP_X_TENANT_ID", "")
return resolve_tenant(code)
tenant = await sync_to_async(_resolve)()
if tenant is None:
raise ValidationError({"tenant": "无法识别租户"})
module_name, model_name, _ = printing_services.DOC_CONTEXT_BUILDERS[doc_type]
model = getattr(__import__(module_name, fromlist=[model_name]), model_name)
def _load_doc():
qs = model.objects.filter(tenant=tenant, pk=document_id)
if doc_type == "sales_bill":
return qs.select_related(
"customer", "warehouse",
).prefetch_related(
"lines__product__base_unit", "lines__source_unit",
).first()
return qs.select_related(
"supplier", "warehouse",
).prefetch_related(
"lines__product__base_unit", "lines__source_unit",
).first()
document = await sync_to_async(_load_doc)()
if document is None:
raise NotFound("document not found")
template_code = request.GET.get("template", "") or ""
autoprint = request.GET.get("autoprint", "1") not in ("0", "false", "False")
html_out = await sync_to_async(printing_services.render_document)(
tenant=tenant, doc_type=doc_type, document=document,
template_code=template_code, autoprint=autoprint,
)
return HttpResponse(html_out, content_type="text/html; charset=utf-8")