打印与标签
打印机路由、ZPL 与 PDF 标签,以及把一次收货或一张完工生产订单变成货架标签的打印任务队列。
Carbon 可以在你过账收货、拆分批次或完成生产订单首道工序时自动打印实体标签。打印系统由打印任务队列、把地点和上下文映射到设备的打印机路由,以及热敏标签 ZPL 和文档 PDF 渲染器组成。
这套系统与发票、采购订单、报价单和生产订单流转卡等生成的 PDF 相互独立。那些文档以文件形式交付;打印则把输出发送到物理打印机。其默认输出是热敏 ZPL 标签。
两种渲染器,一个队列
打印任务按它所路由到的打印机选择两种格式之一渲染:
- ZPL 是热敏标签打印机使用的文本命令语言,是部件标签和存储标签的默认格式。ZPL 标签需要配置了 ZPL 尺寸的介质规格,否则无法渲染。
- PDF 是真正的文档,由生成发票和流转卡的同一套 React-PDF 引擎渲染。看板卡仅支持 PDF,因此发送到仅 ZPL 打印机的看板卡会失败,除非有模板覆盖。
存在三种单据类型(packages/printing/src/registry.ts:10):
Receipt、Shipment、Operation、Entity、Job、Split 或 StockTransfer 打印。StorageUnit 打印。Kanban 打印。来源单据映射到值得打印的单据类型。过账发货会生成产品标签;扫描存储单元会生成存储标签。getDocumentTypesForSource 完成该查找(registry.ts:49)。
打印机路由
打印机路由对应一台物理打印机(printerRoute 表,20260326000000_print-manager.sql:37)。每条路由包含:
https://pbx-XXXX.pbxz.cloud/api/v1/print/…。X-API-Key 头发送。在设置 → 打印中管理路由(apps/erp/app/routes/x+/settings+/printing.tsx)。每条路由都有 Test(测试) 操作,直接向 printerUrl 发送一张小型 ZPL 测试标签,以便在接入工作流之前验证打印机可达。测试打印仅适用于配置了介质规格的 ZPL 打印机,成功时返回 "Test label sent to printer"。
Carbon 通过 ProxyBox 访问打印机,这是车间网络上的 HTTP 端点。Carbon 从不直接连接打印机的原始端口。投递方式是把渲染后的字节 POST 到 printerUrl。如果路由还配置了 templateId 且部署有 BinderyPress 密钥,渲染会委托给 BinderyPress 而不是内置渲染器。
分配:在什么上下文用哪台打印机
路由是打印机;分配决定何时使用它。分配保存在公司的打印设置(companySettings.printing JSONB)中,每个地点一个块。在地点内,你为每个上下文分配打印机(packages/printing/src/assignments.ts:7):
Shipment 时使用。Receipt 时使用。StockTransfer 或 StorageUnit。每个上下文行还带 Auto-print(自动打印) 开关。开启时,匹配的业务事件无需点击即可打印。getPrinterContextForSource 把来源单据映射到上下文,resolveContextAssignment 沿回退链解析:未分配的上下文使用地点默认打印机。
对于没有显式条目的上下文,自动打印开关默认为开启,即使地点默认值的自动打印已关闭。如果希望某地点的发货工位保持静默,请显式设置其 shipping 行,而不要依赖 default 行。
打印机路由使用一小时的 Redis 缓存,键为 printing:{companyId}:{locationId}:{context}。保存路由或分配会使公司缓存的路由数据失效。
打印任务队列
每次打印(手动或自动)都会生成一行 printJob(20260326000000_print-manager.sql:80),并经过一组固定状态:
每个任务记录其 origin,为 auto(业务事件背后的自动打印)、manual(有人点击打印)或 reprint(从任务列表重打)之一。它还保留 sourceDocument、sourceDocumentId、可读 ID、contentType 和发送到的 printerUrl。
在设置 → 打印 → 打印任务(printing.jobs.tsx)中查看队列。表格实时流式更新,显示状态、说明、来源、类型、来源方式和时间。展开行可看到打印机 URL、尝试次数、时间戳和错误。你可以查看内容(ZPL 通过 Labelary 预览,PDF 通过内嵌框架)、重打(生成 origin: "reprint" 的新任务)或删除。
打印任务按计划清理:已完成任务 30 天后,失败任务 90 天后。
自动打印行为
在受支持的业务事件之后,Carbon 解析地点的打印机配置和上下文,检查 autoPrint(未设置时默认开启),并排队一个任务。打印失败不会阻塞触发它的收货、发货或生产订单。
已接入的事件:
| 事件 | 上下文 | 打印内容 |
|---|---|---|
| 过账收货 | receiving | 已收跟踪实体的产品标签。 |
| 过账发货 | shipping | 产品标签,以及批次拆分的 Split 标签。 |
| 拆分库存调拨行 | inventory | 一张 Split 标签,以及原批次的 Entity 重打标签。 |
| 完成生产订单首道工序(MES) | 工作中心 | 生产订单的产品标签。 |
要停止某个工位自动打印,请关闭该地点对应上下文行的自动打印。要改为手动触发打印,请使用相关界面上的打印按钮,或把来源单据发送到手动打印路由(/x/print),它会校验请求并排队同类任务。
同一来源单据的自动打印在 30 秒内去重,Carbon 会丢弃第二个事件。手动打印和重打不去重。
打印与下载
当地点有打印机路由时,打印会打开打印机选择器(默认选中解析出的打印机),确认后排队任务。没有路由时,它会打开下载弹窗,把标签保存为 ZPL 或 PDF。
标签尺寸
介质尺寸是固定目录(packages/utils/src/labels.ts):label2x1、label4x2、公制 label100x50mm 和 label50x25mm,以及仅 PDF 的 avery5163。只有带 ZPL 尺寸的规格才能打印到热敏打印机;像 Avery 这样仅 PDF 的规格不行。
尺寸在两处设置。打印机路由固定自己的 mediaSizeId(该物理打印机装载的尺寸)。公司还有一个默认产品标签尺寸(companySettings.productLabelSize),在单据模板界面设置,在没有路由指定时供交互式标签下载路由使用。该默认值的位置参见公司设置,为内置标签模板设置样式的定制器参见文档。