结论摘要
ai_api -> store 内部交易接口调用链分三层:业务入口负责识别用户和组织订单;ai_api 通过内部接口把一卡通交易交给 store;store 统一调用厂商 API、维护状态机、幂等和补偿。
one_card.enable=false、未配置或查不到有效账户映射时按访客本地钱包运行;查到有效 ydy_one_card_account_map 的一卡通用户才走一卡通。accNum/phoneNo/perCode 数据规则,不是只保存 accStatusNum=1。销户、冻结等变更仍会更新映射;绑盘、余额同步和支付才只放行有效账户和有效当前卡。- 滨州应配置
ewallet_id=2:2 号钱包是补贴,tieEwalletObject中的 1 号钱包是现金。 - 在线消费和离线补传均走
preorder -> orderhandle。 preorder与orderhandle均固定传isCheckCardStatus=1。- 外部接口失败、未知状态、远端成功但本地失败均有交易记录和定时补偿。
通用请求规则
配置来源
外部接口读取 ydy_config.config_key=one_card。真实生产地址、appid、appsecret 和内部鉴权密钥不写入本文。
| 字段 | 作用 | 当前规则 |
|---|---|---|
enable / payment_enable | 身份同步与支付开关 | 滨州约定同开同关 |
business | 本地业务隔离键 | 为空回退 config('business') |
base_url | 一卡通服务地址 | 本文不展示真实值 |
appid / appsecret | token 与签名 | 敏感配置 |
ep_id / area_nums | 项目与区域 | 代码默认均为 1 |
ewallet_id | 查询和消费钱包 | 滨州应为 2 |
payment_business_num | 一卡通消费商户号 | 映射到 dealerNum |
payment_device_map | 设备号映射 | 设备映射优先,其次默认设备号 |
payment_retry_times | 补偿次数 | 默认 3 |
Token
GET {base_url}/api/token?appid={appid}&appsecret={appsecret}
成功响应必须有 access_token 和 expires_in。token 按有效期提前刷新,并用缓存锁避免并发刷新。
业务 POST
POST {base_url}{path}?access_token={access_token}
Content-Type: application/x-www-form-urlencoded
- 除部门水位接口外,表单自动追加
sign。 - 签名:去空值、数组、对象与原
sign,按字段名升序拼接,末尾追加key={appid},取大写 MD5。 - 仅
code="0"视为成功;0001、网络错误、格式错误和缺状态码进入可重试/未知处理。
当前实际调用的外部接口
| # | 业务 | 方法与路径 | 状态 |
|---|---|---|---|
| 1 | Token | GET /api/token | 使用中 |
| 2 | 身份类别 | POST /api/common/queryaccclass | 使用中 |
| 3 | 部门水位 | POST /api/common/systemdocking/getaccdepfixid | 使用中 |
| 4 | 部门增量 | POST /api/common/systemdocking/getaccdepinfobyfixid | 使用中 |
| 5 | 账户水位 | POST /api/common/systemdocking/getaccfixid | 使用中 |
| 6 | 账户及当前卡增量 | POST /api/common/systemdocking/getaccinfobyfixid | 使用中 |
| 7 | 补贴水位 | POST /api/common/getscparamverepbykey | fixType=2 |
| 8 | 补贴包 | POST /api/common/getsubsidypackagebyfixid | 使用中 |
| 9 | 单账户详情 | POST /api/common/infoqueryservice/getaccount | 使用中 |
| 10 | 双钱包 | POST /api/common/infoqueryservice/getewallet | 使用中 |
| 11 | 预下单 | POST /api/common/payservice/preorder | 使用中 |
| 12 | 扣款处理 | POST /api/common/payservice/orderhandle | 使用中 |
| 13 | 查单 | POST /api/common/payservice/orderquery | 使用中 |
| 14 | 冲正退款 | POST /api/common/payservice/correct | 使用中 |
同步类接口与参数
身份类别 · /api/common/queryaccclass
| 字段 | 值来源 | 用途 |
|---|---|---|
epId | one_card.ep_id | 项目/平台标识 |
areaNums | one_card.area_nums | 区域编号 |
sign | 自动生成 | 签名 |
部门水位 · /getaccdepfixid
当前不传业务表单字段,也不传 sign;读取 data.accDepFixId。
部门增量 · /getaccdepinfobyfixid
| 字段 | 值来源 |
|---|---|
startAccDepFixId | 首次 0,否则本地部门水位 + 1 |
endAccDepFixId | 远端最新部门水位 |
sign | 自动生成 |
账户水位 · /getaccfixid
参数:epId=one_card.ep_id、自动 sign;读取 data.accFixId。
账户和当前卡增量 · /getaccinfobyfixid
| 字段 | 值来源 |
|---|---|
startAccFixId | 首次 0,否则账户水位 + 1;指定账户恢复时可等于目标 fixid |
endAccFixId | 远端最新账户水位或目标 fixid |
epId | one_card.ep_id |
sign | 自动生成 |
- 过滤
accNum为空、原始phoneNo为空/非 11 位数字、perCode以-开头的数据。 - 按
business + acc_num更新或创建人员、用户、部门关系、账户映射和当前主卡。 - 手机号占用时写冲突日志,不覆盖本地人员。
- AI 同步失败时不推进本批账户水位。
card命令已转为运行account,没有独立卡增量调用。
补贴水位 · /getscparamverepbykey
参数:epId、固定 fixType=2、areaNums、自动 sign。
补贴包 · /getsubsidypackagebyfixid
| 字段 | 值来源 |
|---|---|
epId | one_card.ep_id |
fixid | 本地补贴水位/本轮游标 |
size | 命令 limit 或批量大小 |
areaNums | one_card.area_nums |
sign | 自动生成 |
补贴包写入本地幂等映射;关联 AI 用户后查询钱包、更新余额镜像,并向 yoshop_user_subsidy_log 写 scene=60 的一卡通补贴发放审计。
账户详情与双钱包
单账户详情 · /api/common/infoqueryservice/getaccount
| 字段 | 当前值 |
|---|---|
encryptFlag | 固定 0 |
epId | one_card.ep_id |
queryType | 固定 1,按账户号 |
uniqueId | 目标 accNum |
photoQueryType | 固定 0,不查照片 |
sign | 自动生成 |
用于手机号冲突解除后的指定账户恢复、手机号回填,以及账户增量缺少当前卡字段时的详情补查。若详情返回 accFixId,系统再精确读取该 fixid 的账户增量行。
钱包 · /api/common/infoqueryservice/getewallet
| 字段 | 值来源 | 滨州口径 |
|---|---|---|
accNum | account_map.acc_num | 一卡通账户号 |
cardAccNum | account_map.card_acc_num | 卡账户号 |
eWalletId | one_card.ewallet_id | 应为 2 |
epId | one_card.ep_id | 通常为 1 |
sign | 自动生成 | 签名 |
tieEwalletObject 内 1 号钱包是现金;本地总余额为两者之和。调用场景包括定时余额、补贴同步、冲突恢复、绑盘、消费前后、冲正前后和补偿后余额校准。
消费、查单与退款参数
预下单 · /api/common/payservice/preorder
| 字段 | 值来源 | 说明 |
|---|---|---|
optType | 固定 5 | 当前消费操作类型 |
uniqueId | account_map.acc_num | 一卡通账户号 |
queryType | 固定 1 | 按账户号定位 |
eWalletNum | one_card.ewallet_id | 滨州为 2,补贴优先、不足再扣现金 |
monTrans | 本地实付金额 | 元,两位小数 |
dealerNum | payment_business_num | 消费商户号 |
dealTime | 在线业务时间/离线设备原时间 | Y-m-d H:i:s |
deviceNum | payload、设备映射、默认设备号 | 按顺序回退 |
proofNum | 本地订单号或离线稳定流水号 | 幂等追踪 |
isCheckCardStatus | 固定 1 | 校验挂失等卡状态 |
sign | 自动生成 | 签名 |
订单处理 · /api/common/payservice/orderhandle
| 字段 | 值来源 |
|---|---|
transRecId | 预下单返回的 transRecId/recId/tradeOrderNo/orderNo |
dealTime | 当前服务器时间 |
proofNum | 与预下单相同的本地稳定流水号 |
recDate | 当前日期 Y-m-d |
payType | 固定 2 |
isCheckCardStatus | 固定 1 |
sign | 自动生成 |
查单 · /api/common/payservice/orderquery
| 字段 | 值来源 |
|---|---|
queryType | 固定 2 |
transRecId | proof_num,为空时为本地订单号 |
liquidationDate | 交易日期转 Ymd,为空用当天 |
sign | 自动生成 |
冲正 · /api/common/payservice/correct
| 字段 | 值来源 |
|---|---|
correctTradeSerial | 原消费 one_card_order_no |
tradeOrderNo | 本地退款单号 |
correctMon | 本次退款金额 |
recDate | 当前日期 Y-m-d |
sign | 自动生成 |
冲正前后分别查询钱包,以实际钱包增量拆分现金退款与补贴退款。相同原订单和退款单号幂等;重复请求金额不一致会拒绝。
完整业务链路
定时同步
OneCardSync all
-> identity
-> department: 水位 -> 增量
-> account/current card: 水位 -> 增量 -> 冲突恢复
-> subsidy: 水位 -> 补贴包 -> 必要时钱包
-> balance: 有效账户与有效当前卡 -> 钱包
OneCardConflictRecovery 每分钟独立重试冲突,解决主水位越过后漏同步的问题;恢复成功后继续补人员、AI 绑定、当前卡、钱包和补贴流水。
绑盘
acc_status_num=1 → 首次绑盘校验本地当前卡有效 → 查询双钱包 → 同步镜像 → 现金+补贴总额参与最低绑盘金额判断。消费机在线
入口为 POST /api/consume/orderPay 或 MQTT,order_type=1:
msgid 防重 → 钱包查询与余额预检 → preorder → orderhandle → 钱包后查询 → 远端成功 → 本地成功订单/流水 → 标记本地成功。消费机离线补传
入口不变,order_type=2,设备端协议不变:
msgid 生成稳定订单号/流水号 → 钱包快照 → preorder → orderhandle → 成功补本地订单;明确失败保留失败交易;未知状态先查单,再由补偿任务处理。离线已经发生现实取餐,失败交易会保存在 ydy_one_card_trade_order 和尝试日志中,支持后台追溯。
绑盘后结算
待支付绑盘订单到结算时间后,一卡通用户走钱包、预下单、扣款和钱包后同步;访客走本地钱包。远端成功、本地失败进入补偿。
小程序余额支付
| local_scene | 场景 | 路径 |
|---|---|---|
ai_meal | 小程序订餐余额支付 | ai_api -> store -> 一卡通 |
ai_direct_pay | 小程序直接金额消费 | ai_api -> store -> 一卡通 |
ai_main | 普通商城余额支付代码路径 | ai_api -> store -> 一卡通 |
访客不调用内部一卡通支付,继续本地钱包。一卡通扣款成功后,AI 侧落本地订单及现金/补贴审计流水。
退款
原订单无成功一卡通交易时按原本地流程退款;有成功一卡通交易时调用冲正。冲正成功但本地退款失败的交易转补偿/人工,禁止重复盲目冲正。
ai_api -> store 内部接口
| 接口 | 请求字段 | 用途 |
|---|---|---|
POST /api/oneCardPayment/consume | local_order_no, local_repo, local_scene, local_order_type, local_order_id, order_source, staff_uuid, user_id, amount, discount_amount, order_snapshot;离线可附 msgid, order_type, deal_time, equipment_code, card_id | 统一发起消费 |
POST /api/oneCardPayment/correct | local_order_no, local_order_id, local_refund_id, local_refund_no, amount/refund_amount, order_snapshot | 冲正退款 |
POST /api/oneCardPayment/query | trade_id 或 local_order_no,可附 trade_type, local_refund_no | 查本地交易 |
POST /api/oneCardPayment/markLocalSuccess | trade_id, local_order_id | 标记两端成功 |
POST /api/oneCardPayment/markLocalFailed | trade_id, error | 进入本地补偿 |
POST /api/oneCardPayment/pendingLocalFailed | local_repo=ai_api, limit | 拉取待补偿交易 |
POST /api/oneCardPayment/markManual | trade_id, error | 转人工 |
鉴权请求头:X-OneCard-Appid、X-OneCard-Timestamp、X-OneCard-Nonce、X-OneCard-Signature。签名使用 HMAC-SHA256,服务端校验时间窗和 nonce 防重放。
保留但当前业务未调用
| 路径/模式 | 代码方法 | 当前原因 |
|---|---|---|
/api/common/getcardaccclassbyfixid | getCardChanges() | 当前卡已合并到账户增量 |
/api/common/getscparamverepbykey + fixType=3 | getCardFixId() | 不单独跑卡水位 |
/api/common/infoqueryservice/querytransaction | queryTransactions() | 交易确认走 orderquery |
/api/common/payservice/hzsunpay/offlinepay | offlinePay() | 离线已改为 preorder → orderhandle |
数据与日志落点
| 表 | 作用 |
|---|---|
ydy_one_card_sync_state | 同步水位、游标、状态和错误 |
ydy_one_card_identity_map | 身份类别映射 |
ydy_one_card_department_map | 部门映射 |
ydy_one_card_account_map | 账户、人员、当前卡、现金/补贴镜像核心映射 |
ydy_one_card_card_map | 当前卡映射快照 |
ydy_one_card_invalid_account_log | 无效账户跳过日志 |
ydy_one_card_account_conflict_log | 手机号冲突与恢复状态 |
ydy_one_card_subsidy_package_map | 补贴包幂等、审计与重试 |
ydy_one_card_trade_order | 消费、离线消费、冲正状态机 |
ydy_one_card_trade_attempt_log | 每次钱包、预下单、扣款、查单和冲正尝试 |
ydy_one_card_trade_repair_log | 自动补偿与人工处理记录 |
aizhct_bzjk.yoshop_user | 现金与补贴余额镜像 |
yoshop_user_balance_log | 一卡通现金消费/退款审计 |
yoshop_user_subsidy_log | 一卡通补贴发放、消费/退款审计 |
运维查看建议
- 接口是否实际调用:查
ydy_one_card_trade_attempt_log.stage和日志[OneCard][api]。 - 同步是否推进:查
ydy_one_card_sync_state,不要只看命令统计。 - 冲突解除后是否补齐:查冲突日志的
status/last_stage/last_error,再核对映射、AI、钱包与补贴包。 - 远端扣款但本地无单:查
status=remote_success_local_failed和修复日志。 - 离线失败:按设备
msgid查交易主表,再看preorder/orderhandle/orderquery尝试记录。 - 查看厂商响应字段:使用
store/tests/e2e/one_card_api_inspect.php,生产只做小范围查询类调用。
代码定位
store/application/common/service/onecard/ApiClient.php · TokenProvider.php · SyncService.php · PaymentService.php · store/application/p/logic/Api.php · store/application/api/service/Consume.php · ai_api/app/common/service/onecard/PaymentClient.php