Files
WareShipManifest/run.py
Misaka_Company 4dc563cdd9 Initial commit
2026-07-30 14:17:18 +08:00

129 lines
4.5 KiB
Python
Raw Permalink 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.
"""装箱单报表生成 CLI。
用法:
python run.py --report packing_list \
--param paichan_no=R04398 --param box_no=1 \
--output out/R04398_box1.pdf
每个报表位于 reports/<name>/ 目录下,约定包含:
query.sql 参数化查询
transform.py build_context(rows) -> dict模板数据
template.report ReportBro 模板 JSON
报表模块需导出 build_context。本入口负责解析参数 → 查询 → 装配 → 渲染 PDF。
"""
from __future__ import annotations
import argparse
import importlib
import json
import sys
from datetime import datetime
from pathlib import Path
# 确保项目根目录在 sys.path便于 python run.py 直接运行)
PROJECT_ROOT = Path(__file__).resolve().parent
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from core.db import run_query # noqa: E402
from core.fonts import additional_fonts # noqa: E402
def parse_params(param_strs: list[str]) -> dict:
"""把 ['paichan_no=R04398', 'box_no=1'] 解析为 {'paichan_no':'R04398','box_no':1}。
数值型字符串自动转 int便于 SQL 参数绑定。
"""
params = {}
for item in param_strs or []:
if "=" not in item:
raise ValueError(f"参数格式错误(应为 key=value{item}")
key, value = item.split("=", 1)
key, value = key.strip(), value.strip()
# 尝试转 int箱号等失败保持字符串
try:
params[key] = int(value)
except ValueError:
params[key] = value
return params
def generate(report_name: str, params: dict, output: str) -> Path:
"""生成指定报表的 PDF。"""
from reportbro import Report # 延迟导入CLI 报错时信息更清晰
report_dir = PROJECT_ROOT / "reports" / report_name
if not report_dir.is_dir():
raise FileNotFoundError(f"报表不存在:{report_dir}(检查 --report 名称)")
# 必需参数校验
required = {"paichan_no", "box_no"}
missing = required - params.keys()
if missing:
raise ValueError(f"缺少必需参数:{', '.join(sorted(missing))}(用 --param key=value 提供)")
# 1. 查询
rows = run_query(report_dir / "query.sql", params)
# 2. 装配模板数据
transform = importlib.import_module(f"reports.{report_name}.transform")
context = transform.build_context(rows)
context["now"] = datetime.now().strftime("%Y-%m-%d %H:%M")
# 3. 渲染:模板元素按数据动态布局(明细行高度自适应)
layout = importlib.import_module(f"reports.{report_name}._build_template")
report_def = layout.build_report_definition(context)
report = Report(
report_definition=report_def,
data=context,
additional_fonts=additional_fonts(),
)
if report.errors:
raise RuntimeError(
f"模板渲染错误({report_name}\n"
+ json.dumps(report.errors, ensure_ascii=False, indent=2, default=str)
)
out_path = Path(output)
if not out_path.is_absolute():
out_path = PROJECT_ROOT / out_path
out_path.parent.mkdir(parents=True, exist_ok=True)
report.generate_pdf(str(out_path))
return out_path
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="生成装箱单 PDF")
parser.add_argument("--report", default="packing_list", help="报表名(默认 packing_list")
parser.add_argument(
"--param", action="append", default=[],
help="报表参数,格式 key=value可多次指定",
)
parser.add_argument("--output", "-o", help="输出 PDF 路径(默认 out/<paichan_no>_box<box_no>.pdf")
args = parser.parse_args(argv)
try:
params = parse_params(args.param)
output = args.output
if not output:
pc = params.get("paichan_no", "report")
bn = params.get("box_no", 0)
output = f"out/{pc}_box{bn}.pdf"
out_path = generate(args.report, params, output)
print(f"✅ 已生成:{out_path}")
print(f" 报表:{args.report} 参数:{params}")
return 0
except FileNotFoundError as e:
print(f"{e}", file=sys.stderr)
except ValueError as e:
print(f"{e}", file=sys.stderr)
except Exception as e: # noqa: BLE001
# 找不到箱等业务错误在此给出清晰提示
print(f"❌ 生成失败:{e}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())