3.5 KiB
3.5 KiB
dealerhub · 打印功能实施报告(P3 #17 打印模板引擎,提前落地)
需求来源:用户提出"需要打印的功能"。对应《差距分析与改造清单》P3 第 17 项(打印模板引擎), 竞品对标:智慧记"多种单据都能打"(小票/A4/三联/标签)、管家婆打印模板。 结果:后端打印中心 + 前端打印按钮全部落地,新增 16 个测试,全量回归 157 passed; 顺带修复一个全项目潜在 bug(detail 路由 404,见下文)。
✅ 功能清单
- 打印模板引擎(注入安全)
- 自研占位符语法:
{{path.to.value}}点路径取值 +{{#each lines}}…{{/each}}行循环 - 所有取值经 html.escape——商品名含
<script>/<img onerror>均被转义(有专项测试) - Django/Jinja 模板标签原样输出不执行——租户编辑模板无法注入逻辑(防模板注入)
- 自研占位符语法:
- 两种单据默认模板(A4 版式、含抬头/明细表/抹零/签收栏/页脚)
- 销售单
sales_bill(XS 单号、客户、仓库、合计行数数量、应收合计) - 进货单
purchase_bill(供应商视角) - 首次渲染自动落库为租户模板(
is_default=True),可在管理界面改
- 销售单
- 打印抬头设置(租户单例):公司名/电话/地址/开户行/页脚备注,渲染时自动注入
{{company.*}} - API
GET /api/v1/printing/render/<doc_type>/<id>/?template=code&autoprint=0|1→ 整页 HTML(带自动打印脚本,可关)GET|POST|PATCH /api/v1/printing/templates/(模板 CRUD)GET|PUT|PATCH /api/v1/printing/settings/default/(抬头单例)
- 前端:销售单/采购单列表加"打印"按钮(仅已过账单可用)——axios 取回 HTML → 新窗口写入 → 浏览器打印对话框自动弹出;
npm run build通过 - 样张:
docs/print_sample.html(含中文抬头、明细、抹零 0.5 元、签收栏的完整样例,浏览器打开即可打印预览)
🐛 顺带修复:全项目 detail 路由 404(潜在 bug)
打印模板的 PUT/PATCH 测试暴露:BaseTenantViewSet.get_queryset 是 async def,
而 adrf 的 aget_object() 同步调用它拿到 coroutine,在 aget_object_or_404 里抛
ValueError 被吞成 Http404——全项目所有 detail 路由(retrieve/PUT/PATCH/DELETE)一直都会 404。
此前未暴露是因为旧测试只覆盖 list 接口。
修复:apps/core/viewset.py 增加覆盖版 aget_object(先 await get_queryset 再过滤/查对象/校验权限),
对全部业务 ViewSet 生效。
📁 变更文件
backend/apps/printing/ [新] models / renderer / services / views / serializers / urls / migrations
backend/config/settings/base.py 注册 apps.printing
backend/apps/core/urls.py 挂载 printing 路由
backend/apps/core/viewset.py [修] aget_object 支持 async get_queryset(全局 detail 路由修复)
backend/tests/test_printing.py [新] 16 例(渲染器安全/语法、上下文、API、租户隔离、转义)
frontend/src/pages/SalesBills.vue · PurchaseBills.vue [新] 打印按钮
frontend/dist/ [重建]
docs/print_sample.html [新] 打印样张
🔜 打印后续可扩展(未做)
- 三联送货单/小票(58mm)版式模板、
{{#if}}条件块、批次号列(批次商品) - 二维码(对账单分享链接直接印在单据上,客户扫码对账)
- PDA/标签打印(蓝牙热敏)