Files
WareShipManifest/README.md
Misaka_Company ee2fab3847 Add A4 carrier print mode (paper=a4) and document it in README + Swagger
- packing_list renders A5 content into top region of an A4 portrait page
  when paper=a4, so A5 paper loaded horizontally in an A4 tray prints upright
- run.generate/print_document/print_api thread the optional paper param through
- README: new Print Service section with A4 carrier usage + curl example
- Swagger: POST /api/print description documents the A4 carrier mode
2026-08-05 16:53:47 +08:00

170 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WareShipManifest · 装箱单报表系统
基于 **ReportBro**`reportbro-lib`,纯 Python生成装箱单 PDF。报表定义SQL / 模板 / 数据装配)均为纯文本,可被 Git 管理后期对接真实打印机时PDF 方案可直接复用。
> 业务背景:把 CargoTrace 成品库分拣系统的装箱数据,打印成装箱单随货流转。
> 一个箱子一份 PDF展示该箱装了哪些内容物总排号及其产品信息。
## 快速开始
```bash
# 1. 建虚拟环境并装依赖
python -m venv .venv
.venv/Scripts/python.exe -m pip install -r requirements.txt # Windows / Git Bash
# 2. 配置数据库(复制模板并填凭据,或直接复用 services/fastapi 的 settings.yaml
cp config/settings.example.yaml config/settings.yaml
# 编辑 config/settings.yaml 填入真实 host/数据库/账号密码
# 3. 生成装箱单
.venv/Scripts/python.exe run.py --report packing_list \
--param paichan_no=R04398 --param box_no=1 \
--output out/R04398_box1.pdf
# → out/R04398_box1.pdf
```
## 用法
```bash
python run.py --report packing_list \
--param paichan_no=<排产号> \
--param box_no=<箱号> \
--output <输出路径.pdf> # 可选,默认 out/<排产号>_box<箱号>.pdf
```
- 缺少参数 → 提示缺少哪个参数。
- 排产号 + 箱号无装箱明细 → 提示「找不到该箱」。
- 均以非零退出码退出,便于脚本集成。
## 报表内容
| 区域 | 内容 |
|---|---|
| 标题 | 装箱单 / PACKING LIST + 分隔线 |
| 信息条 | 排产号、箱号、装箱日期、订单号2×2 网格,标签灰 + 值黑) |
| 列头 | 序号 · 总排号 · 产品型号 · 量程 · 位号 · 数量 · 工令号(小号灰) |
| 明细 | 逐行文本,行间细灰线;无网格边框 |
| 合计 | 合计 N 件(右对齐于数量列下) |
| 页脚 | 生成时间 |
- **无边框、单色、字体驱动**:靠字号 / 字重 / 留白 / 细灰分隔线建立层次,不用表格网格。
- **位号**:合同表字段,多数订单为空,有则显示、无则留白。
- **产品型号**为超长编码串,按列宽换行,行高自适应。
## 数据来源
| 表 | 作用 |
|---|---|
| `CargoTrace.finished_goods_box` | 箱头(排产号 + 箱号 + 装箱时间) |
| `CargoTrace.finished_goods_box_item` | 箱内明细(总排号 + 装入数量) |
| `productionContractData.26年压力表合同数据` / `26年温度计合同数据` | 产品信息(型号/量程/位号/工令号/订单号) |
同一总排号只命中压力表或温度计其中一张表,用双 `LEFT JOIN + COALESCE` 取产品字段,
避免前缀误匹配(`26BW` 不会被 `26B%` 命中)。
## 目录结构
```
WareShipManifest/
├── config/
│ ├── settings.example.yaml # 配置模板(提交)
│ └── settings.yaml # 真实凭据gitignore
├── core/
│ ├── settings.py # 读 yaml → mssql+pyodbc 连接 URL
│ ├── db.py # run_query(sql, params) 参数化绑定
│ └── fonts.py # 中文字体注册simhei via additional_fonts
├── reports/packing_list/
│ ├── query.sql # 参数化查询(:paichan_no / :box_no
│ ├── transform.py # build_context(rows) → 预展开标量参数 + 行高估算(纯逻辑)
│ ├── _build_template.py # 样式 + 运行时按数据动态布局的文档元素(无边框列表式)
│ └── config.yaml # 报表元信息(参数/字段说明)
├── tests/test_transform.py # 纯逻辑单测
├── run.py # CLI 入口
├── requirements.txt
└── README.md
```
## 开发
### 改报表版式(列宽 / 字号 / 边距 / 配色 / 行距)
版式全部在 `reports/packing_list/_build_template.py` 中以代码定义(常量 + 样式工厂)。
文档元素在运行时按数据动态生成(明细行高度自适应),无需预生成模板文件——
直接改代码后重跑 `run.py` 即生效。
> 不使用 ReportBro 可视化设计器,也不用其表格元素(行高不自适应、行不自动堆叠);
> 改用纯文本元素 + 细横线手工排版,坐标完全可控,靠字号/字重/留白建立层次。
### 改查询 / 数据装配
- SQL`reports/packing_list/query.sql`(参数化,禁字符串拼接)。
- 数据装配:`reports/packing_list/transform.py``build_context`(纯逻辑,含单测)。
### 跑测试
```bash
.venv/Scripts/python.exe -m pytest -q
```
### 中文字体
核心字体helvetica 等)无法编码中文,故通过 `core/fonts.py` 注册
`C:/Windows/Fonts/simhei.ttf`(黑体),模板样式 `font="simhei"`
跨机器部署若缺该字体,可用环境变量 `REPORT_CJK_FONT` 指定其它支持中文的 ttf。
## 技术说明
- **reportbro-lib**:纯 Python`pip install reportbro-lib`),无需 Docker / 浏览器 / 设计器常驻服务。
- 数据处理与展示分离:排序在 SQL、合计与日期在 transform、模板只渲染。
- 生成的 PDF 可用 `pymupdf``fitz`)渲染 PNG 做肉眼核对(验证用,非运行时依赖)。
## 打印服务HTTP 接口)
系统内置一个 FastAPI 打印服务(`serve.py` / `core/print_api.py`),把装箱单 / 签收单直接发到物理打印机(后端为 SumatraPDF
### 启动
```bash
.venv/Scripts/python.exe serve.py
# 文档http://<host>:8000/api/docs 健康检查http://<host>:8000/api/health
```
### 调用约定
`POST /api/print`(需 Bearer 鉴权token 见 `config/settings.yaml``api.token`
| 字段 | 必填 | 说明 |
|---|---|---|
| `report_type` | 是 | `packing_list` / `sign_receipt` |
| `params` | 是 | 报表参数:装箱单 `{paichan_no, box_no}`,签收单 `{receipt_no}` |
| `printer` | 否 | 打印机名;缺省用 `printers.default` |
| `dry_run` | 否 | `true` 只生成 PDF 不出纸;默认 `false`(真出纸) |
| `paper` | 否 | 见下方「A4 承载模式」 |
### A4 承载模式(装箱单专用)
现场把 **A5 纸横向装入 A4 纸盒**可避免频繁调卡扣,但横向装载会让 A5 内容在页面上颠倒。
解决方案:传 `"paper": "a4"`,接口会把 A5 内容渲染到 **A4 纵向页面顶部 148mm 区域**,并按 A4 纵向发打印指令——
横向装载的 A5 纸自动承接页面顶部内容,出纸正立、完整。该模式已用真机实测验证。
**启用条件(必须同时满足):**
1. 请求带 `"paper": "a4"`(仅对 `packing_list` 生效,`sign_receipt` 忽略该字段);
2. 物理上 A4 纸盒里的 **A5 纸为横向装载**
标准 A5 托盘(竖向装载)则**不要传 `paper`**,退回 A5 横向直打。
```bash
curl -X POST http://<host>:8000/api/print \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"report_type":"packing_list","params":{"paichan_no":"R07425","box_no":1},"paper":"a4","dry_run":false}'
```
> 承载模式生成的 PDF 文件名带 `_a4` 后缀(`..._a4.pdf`),以别于 A5 直打文件。
> 集成时请直接读取响应里的 `pdf` 字段,勿硬编码路径。
## 路线图
- [x] 对接真实打印机FastAPI + SumatraPDF 打印服务,支持 A4 承载模式)。
- [ ] 发货信息单(地址 / 收件人 / 总件数 / 物料编码)—— 与装箱单拆分,另出报表。