中央缴费机对接.md 31 KB

停车场管理系统对接中央缴费机技术文档


1. 概述

本文档定义了停车场管理系统(SmartParking)与中央缴费机(如 pof-parking-payment-machine)之间的对接规范,涵盖通信架构、接口定义、业务流程及错误码说明。目标是使功能开发者能够依据本文档独立完成缴费机与停车管理系统的集成开发。


2. 通信架构

2.1 网络通信方式

中央缴费机采用 TCP/IP 网络通信方式接入系统 [4],即缴费机与后端服务器通过局域网或互联网建立网络连接。

⚠️ 重要:对接 不是 通过串口串联方式,不是 MQTT 长连接,而是基于 HTTP/HTTPS 的 RESTful API 请求-响应模式。每次业务操作均为独立的 HTTP 请求 [2][7][16]。

2.2 协议选型

实际对接中存在两种协议形式,取决于缴费机型号与系统版本:

协议 传输层 数据格式 适用场景
SmartParking 标准集成协议 HTTPS JSON 外部客户平台(通用缴费机)与 SmartParking 系统集成 [2][17]
POF 缴费机专用协议 HTTP JSON 睿泊科技 POF 缴费机与停车系统后端对接 [7]

下文分别详述两套协议的接口定义。


3. SmartParking 标准集成协议(HTTPS RESTful API)

该协议用于外部客户平台(如中央缴费机)与 SmartParking 系统的标准化集成 [2][16][17]。

3.1 用户认证

接口: POST /sp/login 用途: 获取 accessToken,用于后续所有接口调用的权限验证 [2]

请求参数:

参数 类型 必填 说明
userName String 用户名
passWord String 32位大写 MD5 加密后的密码

请求示例:

{
  "userName": "paystation001",
  "passWord": "E10ADC3949BA59ABBE56E057F20F883E"
}

成功返回:

{
  "accessToken": "xxxxxxxxxxxx",
  "sessionId": "yyyyyyyyyyyy",
  "expireInSeconds": 1800
}

字段说明:

  • accessToken: 访问令牌,有效期 30 分钟,后续接口调用时需使用此值作为会话凭证 [2]
  • sessionId: 会话 ID
  • expireInSeconds: 令牌有效时长(秒)

3.2 按车牌查询费用

接口: POST /sp/charge/payCost 用途: 实时计算当前车辆的停车费用,供缴费机完成预支付 [2][17]

请求参数:

参数 类型 必填 说明
sessionId String 登录返回的 accessToken
carNum String 车牌号
parkingLotCode String 停车场 ID(默认 0001)[2]

成功返回:

{
  "carAccessCurId": "车辆业务ID",
  "freeOutTime": 15,
  "inParkTime": 1714000000,
  "receivableMoney": 12.00,
  "payedMoney": 0.00,
  "favorableAmount": 0.00,
  "ticketNum": "TICKET001"
}

字段说明:

字段 类型 说明
carAccessCurId String 车辆业务 ID,车辆入场后生成,一次进出场业务唯一 [2]
freeOutTime Int 支付后免费出场分钟数 [2]
inParkTime Long 入场时间戳 [2]
receivableMoney Decimal 应收金额(消费金额)[2]
payedMoney Decimal 已付金额 [2]
favorableAmount Decimal 优惠金额 [2]
ticketNum String 票据号 [2]

3.3 支付成功通知

接口: POST /sp/charge/notify 用途: 客户平台将支付账单插入 SmartParking,通知支付成功并触发放行 [2][17]

请求参数:

参数 类型 必填 说明
sessionId String 登录返回的 accessToken
carAccessCurId String 车辆业务 ID(查询费用时返回)[2]
carNum String 车牌号或 UUID(无牌车)[2]
consumeMoney Decimal 消费金额 [2]
consumeTimeStr String 支付时间 [2]
feeAmount Decimal 实际支付金额 [2]
feeType Int 支付方式类型:1-现金,9-支付宝,10-微信支付,16-微信公众号支付 [2]
orderStatus String 订单状态 [2]
parkingLotCode String 停车场 ID [2]
serialNumber String 订单支付流水号(需保证唯一)[2]
ticketNum String 票据号 [2]

说明: [2]

  • 支付成功后 SmartParking 自动查询并放行(未配置出口确认规则时)
  • serialNumber 重复,返回错误码 0021(流水号已存在)

3.4 全局错误码

错误码 说明
0000 成功
0001 失败(具体错误见 errMsg 字段)[2]
0004 登录密码错误 [2]
0006 认证失败,请重新登录 [2]
0007 请求参数不存在 [2]
0017 支付金额不足 [2]
0021 流水号已存在(重复通知)[2]

4. POF 缴费机专用协议(HTTP POST JSON)

该协议定义 POF 停车缴费机与停车系统后端之间的完整接口规范 [7]。

4.1 通用说明

  • 接口类型: HTTP POST
  • 编码: UTF-8
  • 数据格式: JSON
  • 调用失败统一返回: {"Result":0, "Data":{}, "ReMark":"失败原因"} [7]
  • 成功返回: {"Result":1, ...}
  • 认证机制: 除登录接口外,所有业务接口均需携带 Token 参数 [1]

4.2 操作员登录

接口: POST /api/login 用途: 操作员登录,获取 Token,用于后续接口鉴权 [7]

请求参数:

参数 类型 必填 说明
UserName String 用户名
Password String 登录密码,当前必须传明文 UTF-8 字符串;不支持 MD5 或 bcrypt 哈希

请求示例:

{"UserName":"admin","Password":"admin"}

成功返回:

{"Result":1,"Token":"123456"}

4.3 查询车辆费用

接口: POST /api/queryprice 用途: 按车牌查询车辆停车费用 [7]

请求参数:

参数 类型 必填 说明
Token String 认证令牌
Data.CarNo String 查询车牌
Data.QueryTime String 请求时间 yyyy-MM-dd HH:mm:ss

成功返回:

{
  "Result": 1,
  "Data": {
    "OrderId": "123456",
    "CarNo": "B88888",
    "InTime": "2023-04-25 12:00:01",
    "OutTime": "2023-04-26 09:03:23",
    "StopTime": "1小时20分钟",
    "Price": "12",
    "CardNo": "00001",
    "Remark": "收费标准0001",
    "InPic": ""
  }
}

字段说明: [7]

字段 说明
OrderId 订单号(后续所有操作的核心关联标识)[1]
CarNo 车牌号
InTime 入场时间
OutTime 出场时间
StopTime 停放时长
Price 应收金额
CardNo 卡号(月租/会员卡)
Remark 计费规则说明
InPic 入场图片

4.4 支付成功通知

接口: POST /api/paysuccess 用途: 缴费机完成支付后通知后端 [7]

请求参数:

参数 类型 必填 说明
Token String 认证令牌
Data.OrderId String 订单号
Data.CarNo String 车牌
Data.Money String 缴费金额
Data.PayTime String 支付时间 yyyy-MM-dd HH:mm:ss
Data.PayType num 支付方式:0-现金,1-刷卡 [1][7]
Data.PayDev num 支付设备:1-岗亭,2-POF,3-平板 [1][7]
Data.DevId String 设备标识(如 "PoF-01")[1]
Data.ReMark String 备注

4.5 心跳检测

接口: POST /api/heartbeat 用途: 心跳检测,返回服务器时间 [1]

请求参数: Token(认证令牌)

返回: 服务器系统时间。


4.6 推送优惠券

接口: POST /api/ticket 用途: 向订单推送优惠券 [7]

请求参数:

参数 类型 必填 说明
Token String 认证令牌
Data.OrderId String 订单号
Data.CarNo String 车牌
Data.TicketNo String 优惠券编号
Data.TicketType num 优惠券类型:0-减免金额,1-减免时长,2-全免 [1]
Data.Money String 减免金额
Data.Minutes num 减免时间(分钟)
Data.OperTime String 操作时间
Data.ShopName String 商户名称或卡号
Data.ReMark String 备注

4.7 投币明细上报

接口: POST /api/paylist 用途: 上报缴费机投币/找零明细 [7]

请求参数:

参数 类型 必填 说明
Token String 认证令牌
Data.OrderId String 订单号
Data.VoucherNo String 凭证编号
Data.DevIp String 设备 IP
Data.EventDate Datetime 发生时间
Data.InOutType num 0-接收,1-找零 [7]
Data.CoinCashType num 0-硬币,1-纸币 [7]
Data.MValue String 面值
Data.Num Int 数量

4.8 找零失败记录

接口: POST /api/payfail 用途: 记录现金支付找零失败事件 [7]

请求参数:

参数 类型 必填 说明
Token String 认证令牌
Data.OrderId String 订单号
Data.CarNo String 凭证编号(字段名与备注可能不符,需与后端确认)[7]
Data.Intime String 入场时间
Data.Change1 decimal 应收金额
Data.Change2 decimal 实收金额
Data.Change3 decimal 应找零金额
Data.Change4 decimal 实际找零金额
Data.EventTime Datetime 找零时间

4.9 设备状态上报

接口: POST /api/devstatus 用途: 上报缴费机设备运行状态 [7]

请求参数:

参数 类型 必填 说明
Token String 认证令牌
Data.Printer string 0-余量充足,1-余量不足,2-无可用打印纸 [7]
Data.Temperature string 设备温度(摄氏度)
Data.Payment.CurrencyInfo array 货币类型/面值/数量
Data.Payment.Online bool POS 在线状态

4.10 交班登录

接口: POST /api/pof-login 用途: 操作员交班身份验证 [7][19]

请求参数: 与操作员登录接口相同(UserName + Password),返回的 Token 用于交班场景 [7]。


4.11 查询收费总额

接口: POST /api/pof-querymoney 用途: 查询指定设备在指定时间范围内的收费总额,用于交班对账 [7][19]

请求参数:

参数 类型 必填 说明
Token String 认证令牌
Data.DevId String 设备标识(如 "PoF-01")
Data.QueryTime String 请求时间

成功返回:

{"Result":1,"Data":{"TotalMoney":"12","Remark":"收费标准0001"}}

4.12 待完善接口

接口 现状 说明
/api/paystatus 已实现 OrderId 查询数字票和支付状态;具体兼容字段见 4.13
/api/checkpassword 参数已知 密码验证(Data.Password),但具体用途待确认 [7]

4.13 支付状态查询(第二阶段已实现)

接口: POST /api/paystatus 用途: 支付通知超时、网络异常或缴费机重启后,查询订单在管理端的最终支付状态。该接口只读数据库,不会重复扣款或新增支付记录。

请求示例:

{"Token":"登录返回的Token","Data":{"OrderId":"数字票号","CarNo":"湘A12345","DevId":"设备标识"}}

OrderId 必填;CarNoDevId 用于日志及一致性核对,可选。系统仍以 Token 绑定的设备身份认证,并校验设备所属停车场权限。

成功返回:

{"Result":1,"Data":{"OrderId":"...","CarNo":"湘A12345","State":"paid","PayStatus":"paid","PaymentStatus":"paid","Fee":"12.00","Money":"12.00","PaidAmount":"12.00","PayTime":"2026-09-04 12:00:00"},"ReMark":"success"}

PayStatusunpaidpaidState 还可能为 pending_paymentexited 等数字票生命周期状态。订单不存在、车牌不匹配、设备无权访问或 Token 无效时返回 Result=0 及失败原因。

⚠️ 上述接口在实际对接时需与后端开发确认完整定义。 [1][7]


5. 对接业务流程

5.1 正常支付流程

缴费机从查询费用到完成支付的完整流程如下 [9]:

┌─────────┐      ┌──────────────┐      ┌─────────┐
│  缴费机   │      │  停车系统后端  │      │  用户    │
└────┬────┘      └──────┬───────┘      └────┬────┘
     │  1. 用户输入车牌    │                   │
     │──────────────────→│                   │
     │  2. /api/login     │                   │
     │──────────────────→│ 返回 Token        │
     │←──────────────────│                   │
     │  3. /api/queryprice│                   │
     │  (或 /sp/charge/   │                   │
     │   payCost)         │                   │
     │──────────────────→│ 返回车辆信息+费用   │
     │←──────────────────│                   │
     │  4. 用户支付        │                   │
     │                   │                   │←─── 现金/刷卡/扫码
     │  5. /api/paysuccess│                   │
     │  (或 /sp/charge/   │                   │
     │   notify)          │                   │
     │──────────────────→│ 记录支付+放行       │
     │←──────────────────│ 返回成功           │
     │  6. 打印小票        │                   │

流程步骤说明: [9]

  1. 用户在缴费机输入车牌号
  2. 缴费机调用登录接口获取 Token(若 Token 未过期可复用)
  3. 调用查询费用接口获取订单信息(订单号、入场时间、应收金额等)
  4. 用户完成支付(现金、刷卡或扫码)
  5. 缴费机调用支付成功通知接口,携带订单号、金额、支付方式、设备标识等
  6. 后端确认支付成功后标记订单已缴费;车辆到出口后由既有出口确认流程校验缴费状态并放行
  7. 缴费机打印小票(可选步骤,调用优惠券接口进行减免)[9]

5.2 优惠券抵扣流程(可选)

在支付完成前或完成后,可调用优惠券接口(/api/ticket)应用减免 [9]。

5.3 找零失败处理

现金支付产生找零时,若找零失败,通过 /api/payfail 上报记录,便于后续人工处理 [9]。

5.4 交班对账流程

┌─────────┐      ┌──────────────┐
│  缴费机   │      │  停车系统后端  │
└────┬────┘      └──────┬───────┘
     │  1. /api/pof-login│
     │──────────────────→│ 交班登录验证
     │←──────────────────│ 返回 Token
     │  2. /api/pof-querymoney│
     │──────────────────→│ 查询收费总额
     │←──────────────────│ 返回 TotalMoney
     │  3. 核对金额,完成交班│

流程说明: [19]

  1. 接班操作员调用交班登录接口进行身份验证,获取交班会话 Token
  2. 查询当前设备累计收费总额(携带 DevId)
  3. 双方核对金额完成交接
  4. 系统记录交班日志

6. 关键字段速查表

字段 所属协议 说明
Token / accessToken 两套协议 认证令牌,接口鉴权凭证 [2][7]
OrderId POF 协议 订单号,核心关联标识 [1]
carAccessCurId 标准协议 车辆业务 ID [2]
CarNo / carNum 两套协议 车牌号(无牌车用 UUID)[2][7]
Price / receivableMoney 两套协议 应收金额 [2][7]
Money / feeAmount 两套协议 实付金额 [2][7]
PayType POF 协议 支付方式:0-现金,1-刷卡 [1]
feeType 标准协议 支付方式:1-现金,9-支付宝,10-微信,16-公众号 [2]
PayDev POF 协议 支付设备:1-岗亭,2-POF,3-平板 [1]
DevId POF 协议 设备标识(如 "PoF-01")[1]
serialNumber 标准协议 支付流水号(唯一)[2]
TicketType POF 协议 优惠券类型:0-减金额,1-减时长,2-全免 [1]

7. 异常与边界处理建议

7.1 支付金额不足

标准协议中,若实际支付金额低于应收金额,系统返回错误码 0017(支付金额不足)[2]。测试用例显示系统允许部分支付(生成支付记录但不视为完全支付)[6],缴费机应根据业务需求决定是否接受部分支付。

7.2 重复通知

若支付通知的流水号已存在,返回错误码 0021。缴费机收到该错误码时应视为已通知成功,避免重复处理 [2]。

7.3 Token 过期

标准协议中 accessToken 有效期 30 分钟 [2]。收到 0006(认证失败)时应重新调用登录接口获取新 Token。

7.4 网络异常

  • 缴费机侧应实现请求超时重试机制
  • 所有接口为 HTTP 请求-响应模式,无长连接维护 [2][7]
  • 对于离线场景(如断网),建议增加本地缓存和补传机制(PoF 刷卡支付场景尤其重要)

7.5 待确认事项

实际对接时需与后端确认以下问题: [1][7]

  1. /api/devstatus 的完整请求/响应定义缺失;/api/paystatus 已按本项目兼容格式实现
  2. /api/paylistOrderId 参数逻辑(投币明细通常与设备会话相关,而非订单)
  3. /api/payfailCarNo 参数备注为"凭证编号",是否为笔误
  4. /api/checkpassword 的具体业务用途

8. 开发建议

  1. 优先确定协议版本:确认缴费机型号和所对接的后端系统版本,选择对应的协议(标准集成协议或 POF 专用协议)
  2. 模块化封装:按 微型三层架构 将缴费机对接封装为独立模块,便于维护和扩展
  3. 幂等处理:支付通知接口必须实现幂等,处理重复调用场景 [2]
  4. 日志记录:完整记录请求/响应日志,便于排查对账问题
  5. 测试覆盖:参照 智慧停车系统 — 测试用例报告 中部分支付、重复入场、无收费配置兜底等场景设计测试用例 [6]

9. 本项目 POF 实现约定与模拟桩联调

9.1 已实现范围

本项目已按 POF 专用协议实现以下公开 HTTP POST 接口:

接口 实现状态 约定
/api/login 已实现 使用中央缴费机设备账号登录,返回 30 分钟有效的设备 Token
/api/queryprice 已实现 按当前在场会话实时计费,返回数字票号作为 OrderId
/api/paysuccess 已实现 写入支付记录、更新数字票和在场车辆为已支付;不会主动开闸或关闭停车会话
/api/heartbeat 已实现 返回服务器时间

接口统一挂载在后端服务的公开 /api 路径,并在每个业务接口内校验 POF 设备 Token;不会使用后台 Web 用户的 JWT,也不会使用 admin/123456

9.2 订单、支付和出口规则

  1. OrderId 固定映射为 digital_ticket.ticket_no,是本项目 POF 支付的唯一订单标识。
  2. /api/queryprice 只允许查询仍在场、数字票状态为 pending_payment 且未支付的车辆。费用以服务端当前时间实时计算。
  3. /api/paysuccess 必须携带 PayDev=2DevId 作为协议和审计字段记录,但不参与阻断式认证;系统以 Token 绑定的设备身份为准。PayType=0 映射 cash(展示名“现金支付”),PayType=1 映射 pos;若管理员停用了 POS 支付方式,刷卡通知会被拒绝,需先在支付方式配置中启用。
  4. 支付通知前会重新实时算费;Money 与当前应收金额不一致时,返回“金额已变化,请重新查询”。
  5. 缴费成功只标记订单和停车会话已支付。车辆在出口由既有出口流程确认离场和放行,以保留“缴费后免费离场时限”的统一校验。
  6. 厂商协议没有唯一支付流水号。当前按 OrderId + 支付方式 + 应收金额 实现订单级幂等:相同通知重试成功但不会产生第二条收费记录;数据不一致的重复通知失败。所有请求(Token 已脱敏)写入 central_payment_request_log 供联调与对账。

9.3 查询时间兼容

厂商资料的 /api/queryprice 参数表使用 Data.QueryTime,示例却使用 Data.InTime。当前服务同时接收这两个字段,但不将其作为入场时间或计费时间,均以系统已记录的入场时间和服务器当前时间为准。

9.4 模拟桩

启动应用一次后,系统会创建仅用于本地联调的模拟设备:

项目
设备 ID POF-SIM-01
用户名 admin
密码 admin
支付入口 central_payment_machine

安全提示:上述凭据仅限本机或隔离测试网。真机安装前必须禁用或删除该模拟设备,并为每台真机创建独立设备 ID、账号和密码。

先在系统中准备一条未支付的在场车辆记录,再从 lc_garage 目录运行:

go run ./cmd/pof-simulator -base-url http://127.0.0.1:8888 -plate 粤A12345

模拟桩会依次调用 login -> queryprice -> paysuccess -> heartbeat,并打印每个接口原始 JSON 响应。仅验证登录、查询和心跳时使用:

go run ./cmd/pof-simulator -base-url http://127.0.0.1:8888 -plate 粤A12345 -no-pay

生产或局域网部署时,缴费机访问的是后端监听地址,例如 http://<服务器IP>:8888/api/login;不是桌面前端 WebView 内的代理地址。实际端口以 config.yamlsystem.addr 为准。

9.5 联调日志与登录密码格式

中央缴费机请求进入管理端后,后端运行日志会依次输出“收到请求”和“处理成功/失败”两类记录。登录请求包含以下不敏感联调字段:

  • source_ip:缴费机来源 IP;
  • username:提交的设备账号;
  • password_format:密码格式识别结果;
  • password_length:密码字符长度。

系统不会记录登录密码明文、密码哈希或设备 Token。Password 当前必须按 JSON 字符串传输明文,例如 "Password":"admin";日志中的 plain-text_expected 表示格式符合当前协议。出现 md5-32-hex_unsupportedbcrypt-hash_unsupported 时,说明缴费机传入了摘要/哈希值,当前服务会按密码错误处理,设备应改为发送明文密码。

处理结果同时写入 SQLite 的 central_payment_request_log 表,包含 endpointsource_ipdevice_idresultremark 和已脱敏的 request_body,可用于重启后的联调追溯。

应用使用默认配置时,运行日志按日期写入 log\YYYY-MM-DD\info.log(收到请求、处理成功)和 log\YYYY-MM-DD\warn.log(解析或鉴权失败)。实时观察登录联调日志可执行:

Get-Content (Join-Path .\log (Join-Path (Get-Date -Format 'yyyy-MM-dd') 'info.log')) -Wait | Select-String '中央缴费机'

若登录失败,再查看同日期的 warn.log。通过项目管理脚本以 split 模式启动时,标准输出还会同步写入 .run\backend.stdout.log

代码库还提供不依赖真实数据库或硬件的 HTTP 联调回归测试。它以内存 SQLite 建立一条在场订单,并按模拟桩顺序验证 login -> queryprice -> paysuccess -> paystatus -> 重试 paysuccess -> heartbeat,确保状态查询可确认支付结果且重复支付通知不会产生第二笔支付记录:

$env:GOCACHE = (Resolve-Path '.gocache').Path
go test ./internal/modules/central-payment/... -run TestPOFSimulatorHTTPFlow -count=1

9.5 厂商待确认项

以下内容未在当前实现范围内,需在真机到位前向厂商确认后再扩展:

  1. /api/checkpassword 仅给出 Data.Password,没有业务语义,当前未实现。
  2. /api/ticket 的优惠券时机、抵扣规则与本系统收费规则尚未定义,当前未实现。
  3. /api/paylist 投币/找零明细的 VoucherNo 唯一性、补传重试和对账口径未定义,当前未实现。
  4. /api/payfailCarNo 字段说明写为“凭证编号”,字段语义冲突,当前未实现。
  5. /api/devstatusPayment.CurrencyInfo 的数据结构和设备故障处置规则未定义,当前未实现。
  6. POF 支付成功通知没有唯一外部流水号。建议厂商在 Data 中补充稳定且唯一的 VoucherNoSerialNo,以支持跨订单、跨重试窗口的精确幂等和财务对账。
  7. 厂商样例中存在中文引号、缺少逗号等非合法 JSON 的写法;设备必须发送合法 UTF-8 JSON,服务端不会对非 JSON 文本进行猜测性修复。
  8. 厂商资料明确列出 /api/pof-login/api/pof-querymoney,但没有定义交班时段/班次边界,也没有说明 QueryTime 是查询时点还是统计区间。当前未实现,待现场交班和对账口径确认后扩展。

10. 参考资料

编号 资料
[1] 停车系统缴费接口说明补全polan(4)
[2] 自助缴费机集成网络协议(英文版 2025)
[4] POF 停车缴费机硬件规格
[6] 智慧停车系统 — 测试用例报告
[7] 缴费机 API 接口文档
[9] 缴费机支付流程
[16] 自助缴费机集成协议
[17] SmartParking 集成协议
[19] 交班对账机制