票机对接规划.md 7.2 KB

票机对接规划

状态:规划存档,暂缓实施(2026-09-09 评估复杂度后决定推迟) 产出方式:grill-with-docs 设计访谈;领域术语见仓库根目录 CONTEXT.md 重启本项目时:先回答第 6 节 待定决策,再动工

更新 2026-09-09:原 M2(出口自助支付)已拆出并演化为独立设计——LPR + 扫码支付出场,见 doc/扫码支付出场设计.md(车辆识别由"扫小票"改为"车牌识别",订单/渠道/查单/放行联动设计以该文档为准)。本规划仅保留 M1(入场小票闭环)及后续票机增强。

1. 背景与目标

票机是支付的一种入口(对应系统现有支付入口分类 ticket)。目标流程:

入口:车主触发按钮盒 → 票机打印小票(含 ticket_no 二维码)→ 开闸入场
出口:车主在自助终端扫码小票 → 系统生成订单 + 订单二维码(动态、带金额)
     → 车主手机扫码支付(微信支付)→ 回调确认到账 → 自动开闸出场

范围选定为 C:两条链路都做——

  • A. 入场小票闭环:触发端 + 打印机管理前端 + 失败处理(后端打印链路已有 80%)
  • B. 出口自助支付:扫码小票 → 动态订单二维码 → 支付 → 自动出场(全新开发,本期核心)

2. 现状盘点(代码事实,2026-09-09)

模块 现状
internal/modules/printer/ 已对接真实票机:CSN USB DLL(CsnPrinterLibs.dll)+ 串口 ESC/POS(EMD807 79.5mm)双通道;票面含票号二维码;POST /ticket-machine/button 已写好但全仓库无调用方(触发端缺失)
前端 无任何打印机管理/补打 UI;incident 字典已预留 print_failed/reprint 事件类型
数字票 digital-ticket 状态机 created→pending_payment→paid→exited,票号即二维码内容;票机出的票就是数字票的物理载体
支付 payment 支付成功无任何打印/出场钩子ticket_qr 支付方式目前展示静态收款码 + 人工确认,动态订单二维码不存在
中央缴费机 central-payment 独立设备(POF 协议、自带打印、/api/paysuccess 回调),与出口自助终端是两类设备,勿混淆
相关设计文档 docs/superpowers/specs/2026-07-30-ticket-printer-design.mdplans/2026-07-30-ticket-printer-plan.mdplans/2026-07-31-usb-ticket-photo-layout-plan.md

3. 已定决策

# 决策点 结论
1 范围 A + B 都要,入口闭环先行
2 票机硬件 CSN / EMD807 79.5mm 热敏机,已在现场;串口与 USB 都要支持(沿用现有双通道)
3 运营形态 无人岗亭设计,失败处理与自助兜底是一等公民
4 入口触发 按钮盒;v1 用模拟触发,不接实物
5 出口硬件 立式自助终端(参考照片:集成二维码扫描器、IC 读卡区、HELP 对讲按钮、可选出票口);出口车道另有 LPR 摄像机 + LED 屏
6 支付渠道 微信支付先行,先打通测试环节;渠道侧保留抽象以便后续接 KHQR/银行(对应 ADR 提案 0001,未定稿)
7 缴费凭证 第一版不打纸质凭证,出口不装打印机;数字票页面为唯一凭证
8 入口打印失败 自动重试 2 次 → 仍失败照常开闸 + 记 print_failed 事件 + 出口按车牌兜底

4. 核心流程设计(目标态)

入场:按钮盒触发 → POST /ticket-machine/button → 校验通道/绑定设备 → HandlePassage 建会话+数字票 → 打印小票(重试策略见决策 8)→ MQTT 开闸。

出口:车主把小票对准自助终端扫码器 → 终端(后端服务页面)按 ticket_no 解析数字票 → 计费 → 创建订单(锁定金额)→ 生成订单二维码(微信 Native code_url)渲染上屏 → 车主扫码支付 → 微信回调(幂等)→ 订单已支付、数字票转 paid → 自动开闸 → 屏显成功;超时未支付回到初始屏。

5. 领域术语

CONTEXT.md(票机、小票、数字票、扫码、订单、订单二维码、支付渠道、支付入口、自助终端、按钮盒、无人岗亭)。后续讨论与代码命名以此为准。

6. 待定决策(重启时先答)

# 决策点 选项与推荐
1 自助终端内部形态 (a) 标准外设(USB HID 扫描器 + HDMI 屏)自装浏览器 kiosk ✅推荐;(b) 厂商 SDK/协议对接。需确认:设备是否已选型、内部系统、出票口是否为打印机、"Tap the card" IC 读卡 v1 不做是否成立
2 微信商户资料 直连/服务商?mchid、APIv3 密钥/证书、AppID 有无?收款币种(计费 USD/KHR vs 微信 CNY 的跨境问题)?沙箱 or 小额实付
3 道闸控制权 (a) 归我们系统(MQTT 道闸底座)✅推荐;(b) 厂商终端驱动、我们调它的接口
4 丢票兜底范围 推荐 v1 做"按车牌找回会话"(出口已有 LPR 硬件);HELP 对讲 v1 只留物理按键不接系统
5 模拟触发落点 推荐调试接口 + 前端"模拟取票"按钮都要;真实按钮盒通信方式(以太网直连 POST / 边缘盒子 IO)待选型
6 ADR-0001 订单实体 + 支付渠道接口 + 微信先行。提案状态:待批准,批准后写入 docs/adr/0001-payment-channel-abstraction.md

7. 分期实施建议

  • M1 入场小票闭环(工作量小,收益立现):模拟触发入口、打印机管理页(状态/测试页/补打)、打印失败重试 + incident 落库、票机-通道绑定展示。
  • M2 出口自助支付(本期核心):自助终端 kiosk 页面、订单模型与状态机(pending→paid→expired,幂等)、微信 Native 下单 + 回调 + 对账、回调自动开闸、车牌找回兜底、超时回初始屏。
  • M3 增强:真实按钮盒接入、HELP 对讲、缴费凭证打印(硬件已预留出票口)、IC 卡读卡、多支付渠道(KHQR/银行直连)。

8. 风险与依赖

  1. 微信跨境收款:境外停车场用微信收款需跨境商户资质,币种与汇率结算规则要先和渠道方确认——这是 M2 的最大外部依赖。
  2. 自助终端选型:若采购整机带厂商封闭系统,软件主动权旁落;选型时坚持标准外设(USB HID + HDMI)。
  3. 回调可靠性:支付回调可能丢失/迟到 → 必须幂等 + 主动查单兜底 + 对账;"到账即开闸"的体验依赖回调时延。
  4. 金额锁定:订单创建时刻锁定费用,与"缴费后免费离场时限"的交互要定义清楚(超时后补差 or 重新计费)。
  5. 无人值守故障面:缺纸/离线的远程可观测性(仪表盘状态 + incident)在 M1 就要有,不能等 M3。

9. 相关文档

  • CONTEXT.md —— 领域术语表
  • docs/superpowers/specs/2026-07-30-ticket-printer-design.md —— 票机打印原始设计
  • docs/superpowers/plans/2026-07-31-usb-ticket-photo-layout-plan.md —— USB 票面排版
  • doc/中央缴费机对接.md —— POF 协议(另一类设备)
  • doc/设备接入层设计.mddoc/收费流程.mddoc/进出场流程详解.md