# 企油通对接现状分析报告(第一阶段:项目理解与代码调研) > 版本:v1 ・ 生成时间:2026-09-01 > 范围:仅调研,未修改任何代码 / 数据库 / 配置。 > 结论中凡无法从代码确证的,均标注 **【待确认】**。 --- ## 0. 术语与角色对照(先统一叫法) | 报告用词 | 含义 | 代码 / 数据中的体现 | |---|---|---| | **用户** | 终端加油司机 / 消费者 | 小程序用户、下单平台的 `mobile` | | **下单平台** | 调用我们接口的外部对接公司 | `yoshop_partners` 表;样例数据只有 1 家「华集云慧」(`orgNo=S99535450`),回调地址 `https://api.chenan.vip/hmb/oilCardChange` | | **我们的系统** | 本项目 server-tp6 | 对外品牌名「**慧明宝**」(见 `慧明宝供应链平台接口文档V1.0.16.docx`),主体「广西慧明石化有限公司」 | | **上游油品平台 / 四方平台** | 真正出油券、管油站、管核销的上游 | `yoshop_company` 表;目前有两代对接实现,见第 3、4 节 | | **企油通** | 本次要接入的新上游平台 | `企油通接口对接文档.md`,域名 `worknoya.vip` | | 智慧油客 | 上一代上游(`suoyoubao.com.cn`) | `SybOil` / `Crypto`;企油通文档里就是「passageway=3 已停用」的那个通道 | | 定聚 | 当前在用上游(`idingju.com`,中石油 BP `/api/cnpcbp/*`) | `IdingjuOil` / `Idingju` | **关键判断:** 业务链路 `用户 → 下单平台 → 我们的系统 → 企油通` 中, - 「用户 → 下单平台 → 我们的系统」这一段 = **慧明宝入站 API**(`app/api/controller/OilCard.php`),是我们对下单平台的对外契约,**本次仅做最小扩展(新增 `name` 字段),其余 method/URL/字段/加密不变**。 - 「我们的系统 → 上游」这一段 = 用**企油通**整体替换(智慧油客 + 定聚 全部废弃)。 --- ## 0.5 决策记录(2026-09-01 与需求方确认) | # | 议题 | 决策 | |---|---|---| | 1 | 废弃范围 | **智慧油客(`SybOil`) + 定聚(`IdingjuOil`) 两套上游全部废弃**,统一换成企油通;不需要与定聚灰度并存 | | 2 | 企油通企业 | 我们侧**只有一个企业**,`business_license` 为单一配置值;**线下已开通账户**(不需要在系统里做 7.2 创建 / 7.4 开户回调流程) | | 3 | 订单映射粒度 | **一张订单 ↔ 一次 `createAndSendQuota`(7.7)**,其中 1 个 batch → 1 条 waybill → 1 个 employee(该订单的司机) | | 4 | 分油用户来源 | **`yoshop_account` 用户池不保留**;司机信息由**下单平台提供** | | 5 | 小程序油品链路 | **停用**:mobile-uniapp 代码不动,但后端支付成功后**不再触发**任何油品发放/分油/核销逻辑(`PaySuccess::shareOil`、小程序 `order/qrCode(Img)`、`Station.php` 等油品分支停用或摘除) | | 6 | 入站契约变更 | `syb.oil.oilCard.share` **新增 `name`(司机姓名)入参**;**不新增 `id_card`**。其余字段与加密不变 | | 7 | 支付通道 | **默认 = 支付宝企业码(`passageway=1`)**,需配置 `institution_id`;通道值做成**后台/配置可切换** | | 8 | 范围外 | `app/admin` 模块、`yoshop_merchant` 支付聚合链路(`submitOrder`/`Notify`/乐刷)**不在本次范围**,不动 | **由决策派生的新约束(需在方案中处理):** - 决策 6 + 7:`passageway=1` 时 `employee_list` 可不传 `id_card`,只需 `mobile + name + quota_amount + voucher_name + institution_id`,与「下单平台只加传 `name`」正好吻合。 - **但 7.16 司机额度调整 / 7.17 获取支付凭证 均要求 `id_card`(必填)** → 在没有 `id_card` 的前提下,「**撤销分油 / 额度回收**」能力受限(见风险 R-07)。 - 决策 5:小程序历史油券订单(`yoshop_order_goods` 中大量 `zsy_ticket` 数据)后续只读展示,不再有新增。 --- ## 1. 项目架构 ### 1.1 server-tp6(后端,ThinkPHP 6) 多应用结构(`app/` 下按模块分目录): | 模块 | 作用 | 与本次相关度 | |---|---|---| | `app/api` | 对外 HTTP 接口:小程序端 + 下单平台入站 API + 上游回调接收 | ★★★ 核心 | | `app/store` | 后台管理端接口(admin-vue 实际对接的是这里,`renderSuccess` 风格) | ★★★ | | `app/admin` | yoshop 原生后台模块,仅 `controller/{admin,setting,store}`,**疑似未启用** 【待确认】 | ★ | | `app/console` | 命令行 / 队列消费者 / 定时任务 | ★★★ | | `app/common` | 公共 model / service / crypto / enum | ★★★ | - **路由**:`route/app.php` 基本为空,全部走 TP6 默认「模块/控制器/操作」约定路由。 - **多入口文件**(`public/*.php`):除 `index.php` 外,为特定回调 / 场景硬编码了 `PATH_INFO`: | 入口文件 | 绑定路由 | 用途 | |---|---|---| | `public/partners.php` | 透传到 `api` 应用 | 下单平台调用慧明宝 API 的入口(`/partners.php/oilCard/share` 等) | | `public/oil.php` | `/sybNotify/notify` | 上游「分油/发放结果」回调(小程序链路) | | `public/oiluse.php` | `/sybNotify/use` | 上游「加油/核销结果」回调(小程序链路) | | `public/partnersoil.php` | `/sybNotify/partnersNotify` | 上游「分油结果」回调(下单平台链路) | | `public/partnersoiluse.php` | `/sybNotify/partnersUse` | 上游「核销结果」回调(下单平台链路) | | `public/leshua.php` / `public/notice.php` / `public/ocp.php` | — | 乐刷支付 / 通知 / opcache 面板(与油品无关) | - **队列**:Redis(Predis),`app/common/service/QueueService.php`,支持普通队列 + ZSET 延迟队列。消费者在 `config/console.php` 注册: | 命令 | 队列 | 作用 | |---|---|---| | `callback:queue` | `callback_queue` | 处理上游回调(method: `oil` / `use` / `oil_partners` / `use_partners`) | | `partners:queue` | `partners_queue` | 下单平台订单入队后 → 调用上游发放 | | `notify:queue` | `notify_queue` | 我们 → 下单平台的结果回调(带 3 次退避重试 60/300/1800s) | | `card:queue` / `process:queue` / `timer` | — | 兑换卡 / 其他 / 定时任务(与油品无关或次要) | - **其他**:GatewayWorker(WebSocket 推送,`Gateway::sendToUid`);`app/common/lock/RedisLock`(分油抢占锁)。 - **日志**:上游相关日志统一写 `runtime/storelog/{Ym}/{Ymd}/{YmdH}.txt`(`saveLogStore()`)。 ### 1.2 admin-vue(后台管理前端) - 技术栈:Vue 2 + Ant Design Vue(vue-antd-pro 脚手架),`src/config/router.config.js` 静态菜单 + `src/router/generator-routers.js`。 - API 层:`src/api/**`,`axios` 封装(`src/utils/request`),基地址指向 server-tp6 的 `store` 应用。 - 与本次相关的菜单 / 页面见第 6 节。 ### 1.3 mobile-uniapp(小程序端,**本次禁止修改**) - 技术栈:uni-app + uView UI。 - `config.js`:`apiUrl = https://www.hmzkw.com/index.php?s=/api/`,指向 server-tp6 `api` 应用。 - 标准 yoshop 商城客户端(商品 / 购物车 / 结算 / 订单 / 微信支付 / 售后)。 - **仅两处直接触达「油品」语义**(其余全部是服务端在支付成功后自动处理): | api 文件 | 接口 | 服务端 | 依赖上游? | |---|---|---|---| | `api/station.js` | `station/list` | `api/controller/Station.php` → `SybOil::baseGasStationList` | 是(且当前已坏,见风险) | | `api/order.js` | `order/qrCode`、`order/qrCodeImg` | `api/controller/Order.php` → `IdingjuOil::payQrCodeRequest` | 是(核销码/图) | | `api/order.js` | `order/list`、`order/detail`、`order/cancel`、`order/pay` … | 标准商城订单 | 否(间接) | > `order/qrCodeImg` 出参是 `{ base64: "data:image/png;base64,..." }`,服务端通过 `shell_exec("node public/myscript.js ")` 把上游返回的二维码链接转成图片。**这是企油通改造的强约束点**(企油通给的是 H5 免登 URL,不是二维码字符串)。 --- ## 2. 当前订单相关业务流程 ### 2.1 流程 A:小程序商城消费链路(`yoshop_order` + `yoshop_order_goods`) ``` 小程序 goods/list,detail → checkout/submit ── 创建 yoshop_order + yoshop_order_goods(order_type='zsy_ticket',oilCardType='zsy_ticket') → order/pay(微信支付) → 支付回调 → app\api\service\order\PaySuccess::onPaySuccess ├─ updatePayStatus → shareOil($detail) ★ 触发「分油」 │ · getCompany($goods_no) 硬编码 goods_no→orgNo,取 yoshop_company(status=10) │ · processUserOrders($company_id) RedisLock 抢一个「空闲」分油用户(yoshop_account,state=0 且 last_called_at<今天) │ · IdingjuOil::oilOilCardShare(...) → 定聚 /api/cnpcbp/order │ 入参 mobile / out_order_id=oilCardNo / shortname=goods_no / notify_url=oil.php / use_notify_url=oiluse.php │ 出参 code==1,data.trade_no(=shareNo)、data.state(2=已发券)、data.useUrl │ · 回写 order_goods:account_id / company_id / shareNo / oil_status_zsy / oil_status └─ Event 'OrderPaySuccess' → 上游异步回调 public/oil.php (/sybNotify/notify) → 塞 callback_queue(method='oil') → CallbackQueue case 'oil':按 shareNo 命中 order_goods,useStatus==1 → oil_status=1、qrCode=useUrl → 用户点核销 → order/qrCode | order/qrCodeImg → IdingjuOil::payQrCodeRequest(/api/cnpcbp/getUseCode)→ 写 yoshop_order_qrcode → 返回二维码 URL / base64 图 → 加油完成 → 上游回调 public/oiluse.php (/sybNotify/use) → callback_queue(method='use') → CallbackQueue case 'use':写 yoshop_order_record,useStatus==2 → order_goods.use_status=1、use_time 若该 order 下所有 order_goods 都 use_status=1 → yoshop_order.order_status=30(已完成) 释放 yoshop_account(state=0) ``` 订单状态枚举(`app/common/enum/order/`): - `OrderStatus`:10 进行中 / 20 已取消 / 21 待取消 / 30 已完成 - `PayStatus`:10 待支付 / 20 成功 / 30 超时 - `PayType`:10 余额 / 20 微信 / 30 转账 - 油品自定义(在 `order_goods` / `partners_order` 字段上,非枚举类): - `oil_status`:0 未分油 / 1 已分油 - `oil_status_zsy`:1 待处理 / 2 已发券 / 3 发券失败 / 5 已退单(注释写「中石油下单状态」) - `use_status`:0 未核销 / 1 已核销 - `oil_callback` / `use_callback`:是否已回调下单平台 **取消 / 退款**:`app/api/model/Order.php::cancel()` 仅改订单状态(已付款→21 待取消,待后台审核)。`app/common/service/order/Refund.php`、`order/Complete.php` **均不触达上游**——即小程序订单退款/取消**不会**撤销已发放的油券。属流程缺口(见风险 14)。 ### 2.2 流程 B:下单平台对接链路(`yoshop_partners_order`) **入站(下单平台 → 我们,"慧明宝" API,全部 RSA+AES 信封)**,控制器 `app/api/controller/OilCard.php`,鉴权 `app/common/crypto/RsaUtil.php`(平台私钥签名下发 + 合作商公钥验签): | method 头 | 请求 URL | 动作 | |---|---|---| | `syb.oil.oilCard.stockList` | `/oilCard/stock` | 查合作商可下单数量 / 已用 / 未用(读 `yoshop_partners_goods` + `yoshop_partners_order` 计数) | | `syb.oil.oilCard.share` | `/oilCard/share` | 下单:校验 appKey→`yoshop_partners`、`requestId` 幂等(`yoshop_request_log` 唯一索引)、商品/库存/合作商库存校验 → 创建 `yoshop_partners_order`(order_status=10) → 扣 `goods_sku` 库存 → **push `partners_queue`** → 返回 `oilCardNo` + `amount` | | `syb.pay.qrCode.request` | `/oilCard/getPayQrCode` | 申请核销码:`IdingjuOil::payQrCodeRequest` → 写 `yoshop_order_qrcode` | | `syb.oil.oilCard.shareList` | `/oilCard/shareList` | 分油记录分页查询 | | `syb.oil.oilCard.orderStatus` | `/oilCard/orderStatus` | 单笔订单状态查询 | **中段(我们 → 上游)**:`app/console/command/PartnersQueue.php` 消费 `partners_queue`: - 取 `yoshop_partners_order`,`order_status==10 && oil_status==0 && oilCardType=='zsy_ticket'` - `getCompany($goods_no)` 硬编码取 `yoshop_company` - `IdingjuOil::oilOilCardShare(...)`,`notify_url=partnersoil.php`、`use_notify_url=partnersoiluse.php` - 回写 `shareNo / qrCode / oil_status_zsy / oil_status`;若 `state==2` → push `notify_queue`(optType=`share_oil`) **上游回调(上游 → 我们)**: - `public/partnersoil.php` → `/sybNotify/partnersNotify`(method 置为 `oil_partners`)→ `callback_queue` - `public/partnersoiluse.php` → `/sybNotify/partnersUse`(method 置为 `use_partners`)→ `callback_queue` - `CallbackQueue` case `oil_partners`:按 `shareNo` 命中 `yoshop_partners_order`,`useStatus=='1'` → `oil_status=1 / qrCode`,push `notify_queue`(share_oil) - `CallbackQueue` case `use_partners`:写 `yoshop_order_record`,`useStatus=='2'` → `use_status=1 / use_time`,push `notify_queue`(add_oil) **出站回调(我们 → 下单平台)**:`app/console/command/NotifyQueue.php` 消费 `notify_queue`: - 取 `yoshop_partners_order` + `yoshop_partners` - `PartnersOil::sendRequest($partners['callback'], ...)`,header `method='syb.notify.oilCard.change'`,body `{oilCardNo, amount, shareNo, type(add/sub), optType}` - 期望响应 `code=='00'`;成功回写 `oil_callback / use_callback`;失败按 1/3 次退避重试(延迟队列) ### 2.3 流程 C:后台手动运维(admin-vue → app/store) 见第 6 节。核心:手动分油 / 撤销分油 / 补单回调 / 核销码 / 合作商与公司管理 / 分油用户池管理 / 库存同步。 ### 2.4 【待确认】另一条支付聚合链路 `app/api/controller/Order.php::submitOrder / searchOrder`、`app/api/controller/Notify.php`、`yoshop_merchant`(+balance_log+order)、`public/leshua.php`、`config` 中的 `patformKey.php` 等,构成一条「商户 / 代理商 + passageway(WX) + notifyUrl + 乐刷」的**第四方支付聚合**链路,与油券链路数据表有交叉(`order_goods.merchant_id`、`Company::processUserOrders`)。它与本次「企油通油品对接」的关系**未确认**——可能是历史遗留、可能仍在跑。**建议本次不动,单独确认。** --- ## 3. 当前上游(四方平台)对接流程 ### 3.1 第一代:智慧油客 `SybOil`(`suoyoubao.com.cn`)—— **基本已废弃** - 代码:`app/common/service/SybOil.php`(+ 早期 `app/api/controller/syb/Syb*.php` 一组「透传壳」控制器) - 加密:`app/common/crypto/Crypto.php`——RSA(平台公钥加密 AES key) + AES-256-ECB 加密 body + SHA256withRSA 签名,method 头 `syb.*`,接口路径 `/api/1.0.0/...` - 配置:`config/crypto.php`(单租户默认参数)**或** 按 `yoshop_company` 行(`orgNo/appKey/privateKey/publicKey/platformPublicKey`) - 现状: - `CallbackQueue` 里整段 `syb.notify.*` 处理逻辑**全部被注释**,替换为 `oil` / `use` / `*_partners` - `PaySuccess::shareOil` 的 `SybOil` 版本**被注释**,改用 `IdingjuOil` - `yoshop_company` 里 `suoyoubao` / `124.70.136.175` 两行 `status=20`(停用) - **仍在引用但实际已不可用**:`app/api/controller/Station.php`(油站列表,`CompanyModel::detail('2')` 指向停用公司)、`app/store/controller/Goods.php`(库存同步) - 结论:**这是「已废弃的四方平台」最贴切的候选**。 ### 3.2 第二代:定聚 `IdingjuOil`(`idingju.com`,中石油 BP `/api/cnpcbp/*`)—— **当前在用** - 代码:`app/common/service/IdingjuOil.php` + `app/common/crypto/Idingju.php` - 鉴权:`/api/open/getToken`(appid=orgNo, appsecret=appKey)拿 `access_token`,本地缓存到 `public/temp/{orgNo}.txt`(含 `expires_time`);业务请求把 `access_token / timestamp / signature` 拼到 **URL query**,body 为明文 JSON(**不加密**) - 签名:`signature = sha1(api + token + implode(sort(params+token)) + timestamp)` - 多租户:按 `yoshop_company` 行(`status=10` 的 3 行都是 `idingju.com` 域名) - 已实现的接口: | 方法 | 定聚接口 | 用途 | |---|---|---| | `baseGasStationList` | `/api/cnpcbp/stations` | 油站列表(**当前 Station.php 用的是 SybOil,未切到这里**) | | `stockList` | `/api/cnpcbp/queryStock` | 库存(`data.quantity`) | | `oilOilCardSelect` | `/api/cnpcbp/detail` | 订单详情(`out_order_id` 空,形同占位) | | `oilOilCardShare` | `/api/cnpcbp/order` | **下单 / 分油**(`data.trade_no / state / useUrl`) | | `payQrCodeRequest` | `/api/cnpcbp/getUseCode` | **核销二维码**(`data.useQrCodeUrl`) | - 回调:上游 GET/POST 到 `partnersoil.php` / `partnersoiluse.php` / `oil.php` / `oiluse.php`(**当前回调体未验签**,`sybNotify` 里验签代码被注释,直接原样塞队列);回调关键字段 `trade_no`(=shareNo)、`useStatus`('1' 分油成功 / '2' 核销成功)、`useUrl` - 说明:定聚没有「分油成功」的独立推送语义——`oilOilCardShare` 同步返回 `state`,或靠 `partnersoil.php` 回调补。 ### 3.3 出站客户端:`PartnersOil`(不是油品上游,是「回调下单平台」) - `app/common/service/PartnersOil.php`:方法名沿用 `syb.*` 风格,但实际是 POST 到 `yoshop_partners.callback` - 加密:`RsaUtil`(`config/rsa.php` 的平台私钥 + 合作商公钥),与入站 API 同一套信封 ### 3.4 加密类总览 | 类 | 用途 | 算法 | 密钥来源 | |---|---|---|---| | `crypto/Crypto.php` | 智慧油客 SybOil | RSA + AES-256-ECB + SHA256withRSA | `config/crypto.php` 或 `yoshop_company` | | `crypto/Idingju.php` | 定聚 IdingjuOil | token + sha1 签名,body 明文 | `yoshop_company` | | `crypto/RsaUtil.php` | 慧明宝入站 API + 回调下单平台 | RSA(加密 AES key) + AES-256-ECB + SHA256withRSA | `config/rsa.php`(平台私钥文件)+ `yoshop_partners`(合作商公钥) | | (企油通需新建) | — | appId+timestamp+sign(RSA),`params` 为 JSON 字符串;7.15 特殊 MD5→SHA1withRSA;7.16/7.17 强制 RSA 验签 | 线下索取 | --- ## 4. 旧四方平台代码位置(清单) ### 4.1 智慧油客 `SybOil`(第一代,基本死代码) | 文件 | 说明 | |---|---| | `app/common/service/SybOil.php` | 上游客户端(油站/库存/分油/撤销/核销/发票/用户/优惠券等一整套 `syb.*`) | | `app/common/crypto/Crypto.php` | 配套加密 | | `config/crypto.php` | 配套配置(含**明文私钥**) | | `app/api/controller/syb/SybBase.php` `SybOil.php` `SybOrder.php` `SybPay.php` `SybUser.php` `SybVoucher.php` `SybNotify.php` | 早期一组透传壳控制器(`sendRequest` 依赖 `config('crypto.*')`) | | `app/api/controller/SybNotify.php` | **仍在用**(回调入口路由到这里),含 `notify/use/partnersNotify/partnersUse` + 被注释的 `notifyOld` | | `app/api/controller/Station.php` | 油站列表,`SybOil` + 停用公司,实际已坏 | | `app/store/controller/Goods.php`(`stock`/`all` 附近,~L155-211) | 库存同步用 `SybOil::stockList` | | `app/console/command/CallbackQueue.php` | 顶部大段注释的 `syb.notify.*` 处理逻辑(历史实现) | | `app/api/service/order/PaySuccess.php`(~L182-221 注释块) | `SybOil` 版 `shareOil` | ### 4.2 定聚 `IdingjuOil`(第二代,当前在用) | 文件 | 说明 | |---|---| | `app/common/service/IdingjuOil.php` | 上游客户端 | | `app/common/crypto/Idingju.php` | token + sha1 | | `app/console/command/PartnersQueue.php` | 下单平台链路:消费 `partners_queue` → `IdingjuOil::oilOilCardShare` | | `app/api/service/order/PaySuccess.php`(`shareOil()`,~L253-318) | 小程序链路:`IdingjuOil::oilOilCardShare` | | `app/api/controller/Order.php`(`qrCode` L310 / `qrCodeImg` L349) | 小程序核销:`IdingjuOil::payQrCodeRequest` | | `app/api/controller/OilCard.php`(`getPayQrCode`) | 下单平台核销:`IdingjuOil::payQrCodeRequest` | | `app/store/controller/Order.php`(`qrCode` / `share`) | 后台手动核销 / 分油 | | `app/store/controller/partners/Order.php`(`qrCode` / `share`) | 后台合作商订单手动核销 / 分油 | | `app/store/controller/Company.php`(`stock()`) | 后台库存同步 `IdingjuOil::stockList` | | `app/console/command/CallbackQueue.php`(case `oil` / `use` / `oil_partners` / `use_partners`) | 回调处理(当前生效实现) | ### 4.3 出站回调下单平台(本次不改) | 文件 | 说明 | |---|---| | `app/common/service/PartnersOil.php` + `app/console/command/NotifyQueue.php` + `config/rsa.php` + `crypto/RsaUtil.php` | 我们 → 下单平台的结果回调 | ### 4.4 硬编码映射(迁移时必须统一收敛,现散落 7 处) `getCompany($goodsNo)`(`goods_no → orgNo`)与 `getGoodsNo($orgNo)` / `getGoodsNo` 反向映射,重复出现在: `app/api/controller/OilCard.php`、`app/api/controller/Order.php`、`app/api/service/order/PaySuccess.php`、`app/store/controller/Order.php`、`app/store/controller/partners/Order.php`、`app/store/controller/Company.php`、`app/console/command/PartnersQueue.php`。 --- ## 5. 订单创建 / 提交 / 支付 / 取消 / 退款 / 状态同步 / 回调 代码定位 | 环节 | 小程序链路 | 下单平台链路 | 后台 | |---|---|---|---| | 创建 / 提交 | `api/service/order/Checkout.php`、`api/service/order/source/**`、`api/model/Order.php::putInto` | `api/controller/OilCard.php::share` → `api/model/partners/Order.php::saveOrder` | — | | 支付 | `api/controller/Order.php::pay` → `api/model/Order.php::onPay` → 微信支付回调 → `api/service/order/PaySuccess.php::onPaySuccess` | 无「支付」概念(下单即扣合作商库存 / 余额) | — | | **发放 / 分油(触上游)** | `PaySuccess::shareOil()` → `IdingjuOil::oilOilCardShare` | `console/command/PartnersQueue.php` → `IdingjuOil::oilOilCardShare` | `store/controller/Order.php::share`、`store/controller/partners/Order.php::share` | | 核销 / 二维码(触上游) | `api/controller/Order.php::qrCode` / `qrCodeImg` | `api/controller/OilCard.php::getPayQrCode` | `store/controller/Order.php::qrCode`、`store/controller/partners/Order.php::qrCode` | | 取消 | `api/controller/Order.php::cancel` → `api/model/Order.php::cancel`(仅改状态,不触上游) | 无 | `store/controller/Order.php::updatestatus` | | **撤销分油** | `store/controller/Order.php::cancelShare` —— **调用未定义方法 `$this->oilOilCardCancelShare()`,当前会致命错误 / 功能已损坏** | — | admin-vue `CancelShareForm.vue` → `/order/cancelShare` | | 退款 | `common/service/order/Refund.php`(**不触上游**) | 无 | — | | 状态同步(我方←上游) | 回调 `oil.php` / `oiluse.php` → `SybNotify::notify/use` → `callback_queue` → `CallbackQueue` case `oil`/`use` | 回调 `partnersoil.php` / `partnersoiluse.php` → `SybNotify::partnersNotify/partnersUse` → `callback_queue` case `oil_partners`/`use_partners` | 补单:`store/controller/Order.php::callback` / `partners/Order.php::oilCallback` / `useCallback` | | 结果回调(我方→下单平台) | — | `console/command/NotifyQueue.php` → `PartnersOil::sendRequest($partners.callback)` | 手动触发同 `oilCallback` / `useCallback` | | 完成 | `api/model/Order.php::receipt` / `CallbackQueue` 使所有券核销后置 `order_status=30` | `CallbackQueue` 更新 `partners_order` | — | --- ## 6. admin-vue 相关页面 菜单定义:`admin-vue/src/config/router.config.js` | 菜单 | 路由 | 页面文件 | 对接 store 接口 | 与油品对接关系 | |---|---|---|---|---| | 分油公司 › 公司列表 | `/company/index` | `views/company/Index.vue` | `/company/index` `/company/all` `/company/detail` | **上游平台账号管理**(url/orgNo/appKey/privateKey/publicKey/platformPublicKey) | | 分油公司 › 创建 / 编辑 | `/company/create` `/company/update` | `views/company/Create.vue` `Update.vue` | `/company/add` `/company/edit` | 同上;表单字段 = `url, orgNo, appKey, privateKey, publicKey, platformPublicKey` + 公司资料 | | — | modal | `views/company/modules/ApiParaForm.vue` | — | 只读展示对接参数 | | — | modal | `views/company/modules/AccountForm.vue` | `/company/addAccount` | 批量生成随机身份「分油用户」写入 `yoshop_account` | | — | modal | `views/company/modules/RechargeForm.vue` | `/company/recharge` | 公司余额充值(`yoshop_company_balance_log`) | | 分油公司 › 余额明细 | `/company/balance/index` | `views/company/balance/Index.vue` | `/company.balance/*` | 公司余额流水 | | 分油公司 › 分油用户 | `/account/index` | `views/account/Index.vue` | `/account/*` | `yoshop_account` 用户池(小程序分油借用的身份) | | 合作商管理 › 列表 | `/partners/index` | `views/partners/Index.vue` | `/partners/index` `/partners/all` | **下单平台账号管理**(orgNo/appKey/privateKey/publicKey/callback/balance) | | 合作商管理 › 创建 / 编辑 | `/partners/create` `/partners/update` | `views/partners/Create.vue` `Update.vue` | `/partners/add` `/partners/edit` | 含勾选可售商品 + 库存分配(`yoshop_partners_goods`) | | — | modal | `views/partners/modules/ApiParaForm.vue` | — | 只读展示对接参数(含回调地址) | | 合作商管理 › 订单列表 | `/partners/order/index` | `views/partners/order/Index.vue` | `/partners.order/list` `share` `qrCode` `oilCallback` `useCallback` | `yoshop_partners_order` 运维:手动分油 / 核销码 / 重推回调 | | — | modal | `views/partners/order/modules/{OilForm,UseForm,ShareForm,PayForm}.vue` | 同上 | | | 合作商管理 › 余额明细 | `/partners/balance/index` | `views/partners/balance/Index.vue` | `/partners.balance/*` | | | 订单管理 › 全部 / 油券 / 优惠券 | `/order/list/all` `/oil` `/coupon` | `views/order/Index.vue` | `/order/list` `/order/detail` | `yoshop_order` + `order_goods` 运维 | | — | modals | `views/order/modules/{ShareForm,CancelShareForm,FillUpForm,PayForm,CancelForm,DeliveryForm,PriceForm,UpdateStatusForm}.vue` | `/order/share` `/order/cancelShare` `/order/callback` `/order/qrCode` `/order.event/*` | **手动分油 / 撤销分油(当前坏) / 补单 / 付款码** | | 订单管理 › 售后 | (路由已注释,页面文件仍在) | `views/order/refund/**` | — | 当前未启用 | 企油通改造时预计需要动的 admin-vue 页面:**`views/company/**`(改造为企业管理:营业执照 / 通道 / 企业状态 / 开户流程)、`views/order/**` 与 `views/partners/order/**`(补企油通字段、查发放结果、回单下载)**。其余尽量不动。 --- ## 7. 数据库相关表(`oil.sql`,表前缀 `yoshop_`) ### 7.1 下单平台侧 | 表 | 关键字段 | 说明 | |---|---|---| | `yoshop_partners` | `orgNo, appKey, privateKey, publicKey, callback, balance` | 下单平台(对接公司)账号 & 回调地址 & 余额。样例仅 1 条「华集云慧」 | | `yoshop_partners_goods` | `partners_id, goods_id, stock_num, use_num` | 分配给下单平台的可售商品与库存 | | `yoshop_partners_order` | `province, mobile, oilCardType, oilCardNo, shareNo, partners_order_no, partners_id, goods_id/name/no, goods_price, total_price, order_status(10/20/30), qrCode, oil_status, oil_status_zsy, oil_time, oil_text, oil_callback(+time), use_status, use_time, use_text, use_callback(+time), expiration_time` | 下单平台订单主表。**无 user_id**(`user_id=0`)。样例数据 `oil_status_zsy` 多为 3(发券失败,测试环境 `face003`) | | `yoshop_partners_balance_log` / `yoshop_partners_stock_log` | `scene, money / goods_id, num` | 余额 / 库存变动明细 | ### 7.2 上游平台侧 | 表 | 关键字段 | 说明 | |---|---|---| | `yoshop_company` | `url, orgNo, appKey, privateKey, publicKey, platformPublicKey, canOrderNum, unUseNum, useNum, balance, status(10启用/20停用)` | 上游平台账号。样例:row 2/6 = 智慧油客(`suoyoubao` / `124.70...`),`status=20`;row 7/8/9 = 定聚(`idingju.com`),`status=10`,`privateKey/publicKey/platformPublicKey` 存 `'1'`(定聚不用 RSA) | | `yoshop_company_balance_log` | `scene(10充值/20消费/30管理员/40退款), money` | 公司余额流水 | | `yoshop_account` | `userNo, mobile, userName, userIdCard, userType, company_id, state(0空闲/1占用), last_called_at, is_delete` | **分油用户池**——小程序订单分油时「借」一个身份去调上游 | ### 7.3 小程序商城订单侧 | 表 | 关键字段(仅列油品相关) | 说明 | |---|---|---| | `yoshop_order` | `order_no, order_type, order_status(10/20/21/30), total_price, pay_price, pay_type, pay_status, merchant_id, user_id, order_source, platform` | 商城订单主表(yoshop 标准 + `merchant_id` 代理) | | `yoshop_order_goods` | `account_id, userNo, mobile, province, oilCardType, oilCardNo, shareNo, company_id, merchant_id, goods_id/name/no, goods_price, total_price, total_pay_price, qrCode, oil_status, oil_status_zsy, oil_time, oil_text, use_status, use_time, use_text, expiration_time` | **油品状态实际承载在这张表**(一单可多券) | | `yoshop_order_qrcode` | `oilCardNo, qrCode, amount, order_id, order_goods_id, user_id` | 每次申请核销码留痕(样例可见 URL 形态:`https://t-h5.einrkv.com/...`) | | `yoshop_order_record` | `oilCardNo, shareNo, amount, type(add/sub), optType(share_oil/add_oil/cancel_share), order_id, order_goods_id, user_id` | 油卡变动通知落库 | | `yoshop_request_log` | `request_id(唯一), app_key, create_time` | 入站 API `requestId` 幂等去重 | ### 7.4 其他相关 | 表 | 说明 | |---|---| | `yoshop_goods` / `yoshop_goods_sku` | 商品(`goods_no, oilCardType, province, stock_total`)/ SKU(`stock_num`)。库存被「下单减」与「上游库存同步」两套逻辑写 | | `yoshop_merchant` / `yoshop_merchant_balance_log` / `yoshop_merchant_order` | 「商户 / 代理商」体系 + 发券订单,与支付聚合链路相关,**与企油通关系待确认** | | `yoshop_order_refund` 系列 | 售后单(当前后台未启用该菜单) | > 表结构注释在 `oil.sql` 中为 UTF-8;用 `sed`/编辑器读取正常,用 Windows PowerShell `Get-Content` 会乱码。 --- ## 8. 企油通接口清单(据 `企油通接口对接文档.md` 第 7 章,共 23 个) 公共约定: - 全部 `POST`,路径 `/enterprise/api/...`,域名测试/正式不同,**线下索取**。 - 外层信封:`{ appId, timestamp, sign, params }`,其中 **`params` 必须是 JSON 字符串(转义),不是对象**。 - 响应:`{ status: ok|error, data, message, serialNo, sign }`。 - 业务接口**不需要登录态 token**(`appId + business_license` 即可)。 - 金额单位不统一:**分** → 7.7/7.8/7.9/7.10/7.11/7.12/7.13/7.14;**元** → 7.16/7.17/7.19/7.20/7.21/7.23。 - `passageway`:1 支付宝企业码 / 2 平安银行 / 3 智慧油客(🚫停用,勿传) / 4 企油通(仅出现在返回值)。 - `7.16 / 7.17` **必须真实 RSA 验签**,否则 403。 - `batch_no / waybill_no / waybill_no_code` 当前**全平台唯一**,需加企业前缀。 | 编号 | 名称 | 路径 | 用途 / 备注 | |---|---|---|---| | 7.1 | 企业登录(可选) | `/enterprise/api/auth/login` | 业务接口不需要,一般不用 | | 7.2 | 企业申请创建 | `/enterprise/api/zhyk/openAnAccount` | 提交营业执照等,返回待审核;之后线下开户 | | 7.3 | 企业账户信息推送(智慧油客) | 回调 | 🚫 已停用 | | 7.4 | 企业账户信息推送(平安银行) | 回调 `.../callback/ygzf/enterpriseAccountCallback` | 平台→我方,开户完成后推送银行账户 | | 7.5 | 企业账户信息查询 | `/enterprise/api/zhyk/accountQuery` | 查企业账户号/开户行/状态 | | 7.6 | 企业信息查询 | `/enterprise/api/zhyk/getEnterpriseInfo` | `is_new / can_pay / password` | | 7.7 | **运单油费下发** | `/enterprise/api/zhyk/createAndSendQuota` | **核心:给司机按运单发额度**,单批≤100 人,**异步**,`quota_amount` 单位分,平安通道 `id_card` 必填 | | 7.8 | 运单发放结果查询 | `/enterprise/api/zhyk/waybillBatch` | 按 `batch_no` 查发放明细与 `handle_status` | | 7.9 | 运单加油明细查询 | `/enterprise/api/zhyk/waybillQuotaDetail` | 返回 `order_code`(→7.19 回单入参)、加油站、升数、油品、实付 | | 7.10 | **运单加油明细推送(异步)** | 回调 `.../callback/ygzf/waybillConsumeCallback` | 平台→我方,消费推送;**我方须返回 `{"code":"100","msg":"Success"}`** | | 7.11 | 获取企业账户余额 | `/enterprise/api/zhyk/distributable` | 平安实时余额(勿高频轮询);支付宝通道不支持 | | 7.12 | 司机钱包金额查询 | `/enterprise/api/zhyk/driverBalanceQuery` | 司机可用余额(分) | | 7.13 | 司机钱包明细查询 | `/enterprise/api/zhyk/driverWalletQuery` | 流水,默认只回溯近 1 个月 | | 7.14 | 企业发票下载 | `/enterprise/api/zhyk/invoice` | 按月,返回发票地址集 + 加油明细 | | 7.15 | **H5 跳转地址(司机免登加油)** | H5 URL | 替代「核销二维码」;签名:`ksort → http_build_query → urldecode → 大写MD5 → SHA1withRSA → base64`;带 `creditcode` 时须一并入签且企业须 `approved` | | 7.16 | 司机额度调整 | `/enterprise/api/quota/adjustVoucher` | `change_type` 02 增 / 03 减(≈撤销分油),金额**元**,**须 RSA 验签** | | 7.17 | 获取支付凭证 | `/enterprise/api/quota/getVoucherList` | 返回 `quota_id`(→7.16 入参),金额**元**,**须 RSA 验签** | | 7.18 | 司机三证信息保存 | `/enterprise/api/zhyk/saveDriverDoc` | 身份证/驾照/行驶证,含 OCR + 实名二要素;仅更新已存在司机 | | 7.19 | 支付回单获取(平安) | `/enterprise/api/receipt/getPaymentReceipt` | 按 `order_code` 取银行电子回单 PDF;`generating` 需重试(可能 T+1) | | 7.20 | 司机提现到银行卡(平安) | `/enterprise/api/driver-withdraw/withdrawToBank` | 异步,`out_trade_no` 幂等,金额**元** | | 7.21 | 提现结果查询(平安) | `/enterprise/api/driver-withdraw/queryWithdraw` | 轮询至 `success/failed` | | 7.22 | 企业列表查询 | `/enterprise/api/enterprise/list` | 枚举本 appId 名下企业与 `business_license`、已绑定 `passageway`;**需开通权限** | | 7.23 | 平安消费回调测试接口 | `/enterprise/api/zhyk/testPinganConsume` | 🚫 仅测试环境,模拟一笔消费联调 7.10 | **四阶段流程**:① 企业创建(7.2→线下开户→7.4/7.5)② 发放油费(7.7→7.8;额度调整 7.17→7.16)③ 司机加油(7.15→7.9/7.10→7.19)④ 获取发票(7.14)。 --- ## 9. 旧平台接口 ↔ 企油通接口 对应关系 > ⚠️ **前提:两者业务模型不同**(详见风险 1)。下表是「功能意图」层面的映射,不是字段级等价。 | 现有能力(慧明宝入站 method / 上游调用) | 现实现(定聚 / 智慧油客) | 企油通对应 | 差异要点 | |---|---|---|---| | 下单 / 分油 `syb.oil.oilCard.share` → `oilOilCardShare` | 定聚 `/api/cnpcbp/order`,同步返回 `trade_no/state` | **7.7 `createAndSendQuota`**(+ 7.8 查结果) | 由「给手机号发一张固定面值油券」变为「按 `waybill_list.employee_list` 给司机发额度」;**异步**,需 7.8 轮询;平安通道 `id_card` 必填;金额单位分;`batch_no/waybill_no/waybill_no_code` 需加企业前缀 | | 库存查询 `syb.oil.oilCard.stockList` → `stockList` | 定聚 `/api/cnpcbp/queryStock`(`quantity`) | **7.11 `distributable`**(企业资金余额,平安) | 企油通无「油券库存」概念,是**企业账户可发放资金上限**;支付宝通道不支持;勿高频轮询 | | 分油记录查询 `syb.oil.oilCard.shareList` → — | — | **7.9 `waybillQuotaDetail`** / **7.17 `getVoucherList`** | 7.17 须 RSA 验签;返回结构差异大(凭证 / 运单明细) | | 订单状态查询 `syb.oil.oilCard.orderStatus` → — | 读本地 `partners_order` | **7.8 `waybillBatch`**(发放态)/ **7.9**(消费态)/ **7.12**(余额态) | 状态分散在多个接口,无「单笔订单聚合状态」 | | 核销二维码 `syb.pay.qrCode.request` → `payQrCodeRequest` | 定聚 `/api/cnpcbp/getUseCode`(`useQrCodeUrl` 二维码链接) | **7.15 H5 跳转地址(免登)** | **不再是二维码字符串,是 H5 URL**;签名算法完全不同(大写 MD5 → SHA1withRSA);带 `creditcode` 时须企业 `approved`。**小程序 `order/qrCodeImg` 出参 base64 图不能变** → 服务端需把 H5 URL 转二维码图 | | 撤销分油(后台 `cancelShare`,当前坏) | 曾经 `SybOil::oilOilCardCancelShare` | **7.16 `adjustVoucher`**(`change_type=03` 减额度) | 须 RSA 验签;金额单位元;先 7.17 拿 `quota_id` | | 分油结果回调 `partnersoil.php` / `oil.php`(method `oil`/`oil_partners`,`trade_no`+`useStatus=1`) | 定聚主动推 | **无对应推送** → 改为主动查 **7.8** | 企油通发放无「成功推送」,须轮询 | | 加油/核销结果回调 `partnersoiluse.php` / `oiluse.php`(method `use`/`use_partners`,`useStatus=2`) | 定聚主动推 | **7.10 `waybillConsumeCallback`** | 回调地址由我方提供并配置;**我方须返回 `{"code":"100","msg":"Success"}`**(现有返回 `OK` / `{"code":"00"}`,不匹配) | | 油站列表 `syb.base.gasStation.list` → `baseGasStationList` | 定聚 `/api/cnpcbp/stations`(Station.php 却用 SybOil,已坏) | **文档无公开油站接口**(H5 内自带选站) | 小程序 `station/list` 需重新评估:或保留定聚、或去掉、或改为静态/其它源 **【待确认】** | | 发票(SybOil 有 `payInvoiceRequest/Status`) | 未接入下单平台链路 | **7.14 `invoice`** | 按月企业维度 | | 我方 → 下单平台回调 `syb.notify.oilCard.change`(`PartnersOil`) | 生效 | **保持不变**,内部把企油通字段翻译回该结构 | 契约层,不改 | | 企业开户 / 账户 | **旧系统无此概念**(`yoshop_company` 直接填 orgNo/appKey) | **7.2 / 7.4 / 7.5 / 7.6 / 7.22** | 全新流程:企业创建须审核 + 线下开户 + 异步回调 | | 司机建档 / 三证 | 旧系统「借」`yoshop_account` 池身份 | **7.18 `saveDriverDoc`** + 7.7 `employee_list` 建档 | 实名二要素核验;司机须属于企业 | | 提现 | 无 | **7.20 / 7.21**(新增能力,平安) | 可选 | --- ## 10. 当前发现的问题与风险(已按 0.5 决策收敛) > 图例:✅ 决策已消解 ・ 🔴 待处理阻塞项(需你拍板 / 需对接人补料) ・ 🟡 施工注意项 | # | 风险 | 级别 | 结论 / 处理方向 | |---|---|---|---| | R-01 | 业务模型差异(油券库存 vs 企业运单额度) | ✅ | 决策 2/3/4:单企业 + 一张订单一次 `createAndSendQuota`(1 batch / 1 waybill / 1 employee);「商品面值」= `quota_amount`(元→分);不再有「平台油券库存」概念 | | R-02 | 「废弃四方平台」范围 | ✅ | 决策 1:`SybOil` + `IdingjuOil` 全部废弃,不灰度并存 | | R-03 | 企业开户不可即时(7.2→7.4) | ✅ | 决策 2:线下已开户,系统内**不实现** 7.2/7.4,`business_license` 直接配置;7.5/7.6/7.22 作可选核对 | | R-04 | 发放异步两段式(7.7 受理 → 7.8 轮询) | 🟡 | 新增 `qyt_poll_queue` 延迟队列轮询 7.8;`partners_order` 增发放态字段 | | R-05 | 无「发放成功」推送 | 🟡 | 同 R-04,靠轮询 7.8 `handle_status` 驱动 `notify_queue` | | R-06 | 核销形态:二维码字符串 → H5 免登 URL(7.15) | 🟡 | 下单平台链路 `getPayQrCode` 出参 `qrCode` 直接放 H5 URL(本就是链接,下单平台侧生成二维码逻辑不受影响);7.15 特殊签名需新写。小程序 `order/qrCodeImg` 因链路停用(决策 5)不涉及 | | R-07 | 7.16/7.17 需 `id_card`,但下单平台不传(决策 6) | 🟡→🔴 | 决策 9:**撤销/退款做**(企油通有 7.16)。但 7.16 的 `quota_id` 来自 7.17,而 7.17 需 `id_card`。落地方案:先尝试从 7.7 受理响应 / 7.8 结果 / 7.9 明细里拿到可用的凭证标识并落库(`quota_id`);若均拿不到 → 撤销请求要求下单平台补传 `id_card`。**具体以联调时对接人确认的「7.16 定位方式」为准(R-19)** | | R-08 | 金额单位混用(分/元) | 🟡 | 新增单位换算 helper,`QytOil` 内部统一 | | R-09 | 全平台唯一编号需企业前缀 | 🟡 | 定义前缀规则(如 `HM` + 环境标识),`batch_no/waybill_no/waybill_no_code` 由 `saleOrderNo`/`order_id` 派生并落库 | | R-10 | 库存查询语义(`syb.oil.oilCard.stockList` → `/oilCard/stock`) | ✅ | 决策:企油通没有就不接。接口壳保留(防下单平台报错),数据来源改为我方 `yoshop_partners_goods.stock_num`(后台仍可分配),不再调用上游;`Company::stock` / `store/Goods.php` 的上游库存同步移除。**【待确认下单平台是否仍调用该接口】**,如不调用后续可直接下线 | | R-11 | 签名/加密体系全新 | 🟡 | 新建 `app/common/crypto/Qyt.php`(业务信封 RSA 签名 + 7.15 H5 特殊签名 + 7.16/7.17 RSA 验签) | | R-12 | 7.10 回调需返回 `{"code":"100","msg":"Success"}` 且需验签 | 🟡 | 新回调入口独立实现,不复用 `SybNotify` 的 `OK` 返回 | | R-13 | `store/controller/Order.php::cancelShare` 调用未定义方法(已坏) | 🟡 | 属小程序链路(决策 5 停用);本次移除该分支或改指向「按订单 7.16 撤销」(受 R-07 约束) | | R-14 | `goods_no ↔ orgNo` 硬编码散落 7 处 | 🟡 | 单企业后 `orgNo` 概念消失,`goods_no → voucher_name/面值` 收敛为 `config/qyt.php` 映射或读 `yoshop_goods` | | R-15 | 退款/取消无上游回收 | 🟡 | 决策 9:做。新增入站 method `syb.oil.oilCard.cancelShare`(.docx 未定义,属慧明宝契约小扩展)→ 我方查凭证 → 7.16 `change_type=03` 减额度 → 回写 + 回调下单平台(optType=cancel_share, type=sub) | | R-16 | `Station.php` / `store/Goods.php` 依赖已停用 SybOil | 🟡 | 决策 5:一并停用/摘除;`store/Goods.php` 库存同步改为不依赖上游 | | R-17 | `app/admin`、`yoshop_merchant` 支付聚合 | ✅ | 决策 8:范围外,不动 | | R-18 | 敏感信息明文(config/DB 私钥) | 🟡 | 企油通密钥放 `config/qyt.php` + `.env`,不写进 `yoshop_*` 表 | | R-19 | 环境参数需线下索取 | 🔴 | 需对接人给:测试/正式域名、`appId`、业务密钥/公私钥、`institution_id`、7.10 回调地址配置方式、7.15 落地页 appId | | R-20 | 文档只覆盖第 7 章 | 🔴 | 7.15 落地页参数、`institution_id` 分配、拼签字段明细需补 | | R-21 | 小程序历史油券订单数据 | 🟡 | `yoshop_order_goods` 大量 `zsy_ticket` 旧数据只读保留;后台订单页兼容旧/新字段展示 | ### 决策补充(2026-09-01 第二轮) | # | 议题 | 决策 | |---|---|---| | 9 | 撤销 / 退款 | **做**(企油通有 7.16 `adjustVoucher`)。新增入站 method `syb.oil.oilCard.cancelShare` → 我方定位凭证 → 7.16 `change_type=03` 减额度 → 回写 + 回调下单平台。凭证定位方式(是否需 `id_card`)以联调时对接人确认为准 | | 10 | `/oilCard/stock` 库存 | 企油通没有就不接。接口壳保留、数据取我方 `yoshop_partners_goods`,不再同步上游 | | 11 | 回调下单平台字段 | **不硬凑**。所有字段严格按企油通实际返回来填,企油通没有的(如旧 `shareNo`)就填空 / 不下发。发放阶段 `shareNo` 可留空或填 `waybill_no_code`;消费阶段填企油通 `order_code` | | 12 | 后台范围 | 「满足接口 + 满足运营」——凡企油通有、运营用得上的都进后台:发放结果查询(7.8)、加油明细(7.9)、H5 加油链接(7.15)、消费流水、企业余额(7.11)、企业信息(7.5/7.6)、发票下载(7.14) | ### 决策补充(2026-09-01 第三轮 · 施工细节) | # | 议题 | 决策 | |---|---|---| | 13 | 企油通订单字段落库 | 直接加到 `yoshop_partners_order` 主表(不建关联表);发放态复用 `oil_status_zsy` | | 14 | `name` 缺失 | 兜底占位(`"司机"+手机尾4位`),不阻断下单 | | 15 | `qrCode` 返回 | 直接把 7.15 H5 URL 放进 `qrCode` 字段,不转二维码图 | | 16 | 发放结果获取 | 延迟队列退避轮询 7.8(新增 `qyt_poll_queue` + `qyt:poll` 命令) | | 17 | 7.10 消费回调入口 | 新建独立入口 `public/qytconsume.php` | | 18 | 小程序油品链路 | 后端停止触发,相关代码**保留不删** | | 19 | 旧上游代码(SybOil/IdingjuOil/…) | 本期保留不删、只停止调用;全链路联调通过后在收尾阶段统一删除 | | 20 | 后台「企业管理」 | 改造现有「分油公司」菜单为「企业管理」页(复用菜单/路由/权限) | | 21 | 施工节奏 | 先出 DB 迁移 + `config/qyt.php` + `Qyt.php` / `QytOil.php` 骨架审核,确认后再动队列/控制器 | ### 仍需对接人提供(R-19/R-20,阻塞联调,不阻塞脚手架开发) 测试 + 正式域名、`appId`、业务 RSA 公私钥与**业务接口拼签字段顺序**、`institution_id`(支付宝企业码通道必填)、7.10 回调地址如何配置、7.15 H5 落地页 `appId` 与签名字段清单、7.16 凭证定位方式。 --- ## 附 B. 第二阶段 A-1 交付物(骨架,待审) | 文件 | 状态 | 说明 | |---|---|---| | `server-tp6/qyt_migration.sql` | 新增 | `yoshop_partners_order` 加 14 字段 + 2 索引;新建 `yoshop_qyt_consume`;含回滚脚本。**执行前请审字段** | | `server-tp6/config/qyt.php` | 新增 | 配置骨架;标 ★ 的值待对接人给(用 `.env` 覆盖) | | `server-tp6/app/common/crypto/Qyt.php` | 新增 | 业务信封 / 7.15 H5 签名 / 验签;`bizSign()` 的拼签规则标 **TODO 待对接人确认**(默认走 7.15 同族算法) | | `server-tp6/app/common/service/QytOil.php` | 新增 | 企油通客户端:7.7/7.8/7.9/7.11/7.14/7.15/7.16/7.17;元↔分、编号生成、日志工具 | > 均为**新增文件,未触碰任何现有文件**。审核通过后再进入 A-2(改 `PartnersQueue` / 新增 `QytPollQueue` / `QytNotify` / 改 `OilCard.php` / 改 `CallbackQueue`)。 --- ## 附 C. 第二阶段 A-2 交付物(下单平台链路打通,待审) > ⚠️ **部署前必须先执行 `qyt_migration.sql`**(`yoshop_partners_order` 会用到新列)。 ### 新增文件 | 文件 | 说明 | |---|---| | `app/console/command/QytPollQueue.php` | `qyt:poll` 命令:退避轮询 7.8 拿发放结果,成功→写订单+投 `notify_queue`;超次数标记人工核对 | | `app/api/controller/QytNotify.php` | `/qytNotify/consume`:接收 7.10,验签(TODO),落 `callback_queue`(method `qyt_consume`),返回 `{"code":"100","msg":"Success"}` | | `public/qytconsume.php` | 7.10 回调入口(配到企油通后台的地址) | ### 改动文件(现有) | 文件 | 改动 | |---|---| | `config/console.php` | 注册 `qyt:poll` | | `app/console/command/PartnersQueue.php` | 整个 `processMessage` 重写:`IdingjuOil::oilOilCardShare` → 生成企业前缀编号 + `QytOil::createAndSendQuota`(7.7 受理) → 受理成功投 `qyt_poll_queue`。删除硬编码 `getCompany()` | | `app/console/command/CallbackQueue.php` | **仅新增** `case "qyt_consume"`(写 `yoshop_qyt_consume` + 更新订单核销 + 投 `notify_queue`);旧 `oil/use/oil_partners/use_partners` 分支保留不动 | | `app/api/controller/OilCard.php` | ①`use QytOil` ②`share()` 加 `name` 入参 + 兜底占位 + `saveOrder` 增 `driver_name/passageway` ③`getPayQrCode()` 改 `QytOil::h5Url`(出参 `qrCode` 结构不变)④**新增 `cancelShare()`**(method `syb.oil.oilCard.cancelShare` → 7.17 定位 `quota_id` → 7.16 减额度 → 投 `notify_queue` optType=`cancel_share`)。`getCompany()`/`IdingjuOil` import 保留(死代码,收尾清) | | `app/api/service/order/PaySuccess.php` | `shareOil()` 的 `zsy_ticket` 分支加 `continue` —— 小程序支付成功后不再触发上游(优惠券分支保留) | ### A-2 新增待确认 - **`optType=cancel_share`**:`NotifyQueue` 把撤销通知发给下单平台时 `type=sub / optType=cancel_share`(`.docx` 回调 optType 枚举只有 share_volume/share_oil/add_oil)。需与下单平台确认能否识别,或改用其约定值。 - **7.7 响应 `data.status`**:文档写 `1 成功 / 2 失败`,此处「成功」按「受理成功」处理;如企油通实际语义不同需调 `PartnersQueue`。 - **7.8 `list[].handle_status`**:按 `1待处理/2成功/3失败` 匹配;如字段名/取值不同需调 `QytPollQueue`。 ### 未动(留给 A-3) 小程序核销 `app/api/controller/Order.php::qrCode/qrCodeImg`、`Station.php`、`store/controller/Order.php`(小程序订单后台)、`store/controller/Company.php::stock`、`store/controller/Goods.php`、`store/controller/partners/Order.php`(下单平台订单后台运维)、admin-vue 页面。 --- ## 附 D. 并发 / 原子性加固(A-2 补丁,已并入 A-2 交付物) ### 状态机(`yoshop_partners_order`) | `oil_status_zsy` | 含义 | 迁入方 | 迁入条件 | |---|---|---|---| | 0 | 未提交 | 建单默认 | — | | 1 | 已受理待发放 | `PartnersQueue` | `WHERE oil_status_zsy=0`(7.7 受理成功后) | | 2 | 发放成功 | `QytPollQueue` | `WHERE oil_status=0 AND oil_status_zsy=1`(7.8 handle_status=2) | | 3 | 发放失败 | `PartnersQueue` / `QytPollQueue` | `WHERE oil_status_zsy IN (0,1)`(7.7 拒绝 / 7.8=3 / 轮询超时) | | 5 | 已撤销 | `OilCard::cancelShare` | `WHERE oil_status=1 AND oil_status_zsy=2 AND use_status=0`(7.16 成功) | `use_status` 0→1:`CallbackQueue` `WHERE use_status=0 AND oil_status=1`(7.10 消费)。 **每个状态迁移都是条件 `UPDATE ... WHERE 期望值`,`affected_rows=1` 的进程才推送下游队列** → 天然幂等,可多进程 / 重复消息安全。 ### 具体措施 | 场景 | 风险 | 措施 | |---|---|---| | `OilCard::share` 同一 `saleOrderNo` 并发 | 先查后插竞态 → 重复建单 / 库存超扣 | DB 唯一键 `uk_partner_saleorder(partners_id, partners_order_no)`;命中已存在订单 → **幂等返回原结果**;`saveOrder` 捕获 Duplicate 再幂等返回 | | `PartnersQueue` 同一 order 被多 worker / 重复消息处理 | 重复调 7.7 | `RedisLock('qyt:send:{order_id}', 60s)` 串行 + 锁内重读状态;`batch_no` 确定性派生,重试用同一值,依赖企油通按 `batch_no` 幂等(`dup_batch_hints` 命中即按已受理处理) | | 7.7 成功但 worker 崩溃(未及入轮询队列) | 订单卡在「已受理」永不发放 | `oil_status_zsy` 只在 7.7 结果确定后离开 0;`QytPollQueue::reconcile()`(空闲每 60s)补投:`oil_status_zsy=0` 超 2min → 重投 `partners_queue`;`oil_status_zsy=1` 且 15min 无进展 → 重投 `qyt_poll_queue` | | `QytPollQueue` 多 worker / 延迟队列并发迁移 | 同一 order 重复 7.8 → 重复回调下单平台 | `QueueService::migrateDelayedToReady` 改为**先 `zrem` 抢占再入队**;发放成功用条件 UPDATE 1→2,仅胜出者推 `notify_queue` | | 企油通重推 7.10 | 重复消费流水 / 重复回调 | `yoshop_qyt_consume` 唯一键 `uk_consume(waybill_no_code, order_code)` + 插入捕获 Duplicate;`use_status` 条件跃迁 0→1,仅胜出者推 `notify_queue` | | `cancelShare` 并发 / 与 7.10 消费竞争 | 重复调 7.16 减额度 / 撤销与加油冲突 | `RedisLock('qyt:cancel:{order_id}', 60s)` + 条件占位 `WHERE oil_status_zsy=2 AND use_status=0`;7.16 失败回滚 `oil_text`;成功再条件跃迁 2→5(仍要求未核销),冲突则返回人工核对 | | `callback_queue` / `notify_queue` 单消费者假设 | 与旧代码一致 | 建议单进程;即使多进程,因全链路条件跃迁,最坏只是日志重复 | ### 遗留(联调时与对接人确认) - **7.7 幂等键**:确认企油通是否严格按 `batch_no` 去重,重复提交返回什么(用于 `dup_batch_hints` 精确匹配)。 - **7.16 幂等**:文档无幂等键;当前靠 `RedisLock` + 条件占位防重,但跨进程锁过期(60s)后仍有极小窗口。若企油通提供幂等键(如 `out_trade_no`)应接入。 - **`RedisLock`** 用 `config('redis')`,`QueueService` 用硬编码 `127.0.0.1:6379` —— 生产需统一(本次未动 `QueueService` 连接配置)。 --- ## 附 E. 对下单平台接口文档更新(`慧明宝供应链平台接口文档V1.0.17.docx`) 在原 `V1.0.16.docx` 基础上做增量修改,保留原文件为历史。改动: | # | 章节 | 变更 | |---|---|---| | 1 | 3.2.1 用户分油 请求体 | 新增 `name`(司机姓名,可选,String V50,缺失平台兜底) | | 2 | 3.5.1 油卡变动通知 `optType` | 新增取值 `cancel_share`(撤销分油,配 `type=sub`) | | 3 | 文末新增《附录:V1.0.17 变更说明》 | ①`share` 增 `name` + 异步发放语义 + `saleOrderNo` 幂等;②**新增接口 `syb.oil.oilCard.cancelShare`**(撤销分油,`/oilCard/cancelShare`,入参 `orgNo` / `oilCardNo` 或 `saleOrderNo` / `id_card`,出参 `oilCardNo` `amount`);③`qrCode.request` 返回值由二维码串改为 H5 免登地址;④`stockList` 返回值改为平台内部额度统计;⑤`notify` 空值兼容说明;⑥修订记录 | 制作方式:`unpack → merge_runs.py → 编辑 document.xml → 重新打包`,`validate.py` XSD 校验通过。 **注意**:①本机无 LibreOffice,未能渲染 PDF 目视核对,建议用 Word 打开确认排版;②新增《附录》为普通标题,不在目录中,Word 打开时可「更新域」重建目录;③`merge_runs` 合并了冗余样式标签(内容与渲染不变),故 `.docx` 体积小于原文件属正常。 --- ## 附 F. 范围收敛(2026-09-03 · 最终版)—— 支付宝企业码通道,仅 3 个上游接口 > 需求方最终确认:**只对接支付宝企业码通道**,上游实际只用 3 个接口: > **7.7 运单油费下发 / 7.15 H5 跳转地址 / 7.10 运单加油明细推送(异步回调)**。 > 司机姓名 + 手机号由下单平台必传。不做撤销(企油通仅 7.16 调整额度,本期不用)。 > 本节内容**取代**前文附 B / C / D / E 中与轮询、撤销、平安通道、7.8/7.9/7.11/7.14/7.16/7.17 相关的描述。 ### 与之前版本的差异 | 项 | 之前(附 B/C/D) | 现在(最终) | |---|---|---| | 上游接口 | 7.7 + 7.8 轮询 + 7.15 + 7.10 + 7.16/7.17 撤销 + 可选 7.9/7.11/7.14 | **仅 7.7 + 7.15 + 7.10** | | 发放结果 | 7.7 受理 → `qyt_poll_queue` 退避轮询 7.8 | **7.7 受理成功即视为发放成功**(支付宝企业码通道),直接回调下单平台。删除 `QytPollQueue` / `qyt:poll` / `qyt_poll_queue` | | 通道 | 1/2 可切换 + `institution_id` | **固定 `passageway=1`**(支付宝企业码)+ `institution_id` 必填 | | 司机姓名 `name` | 可选,缺失兜底占位 | **必填**,下单平台不传 → 返回 `0001 缺少必填请求参数 name`。(`mobile` 本就必填) | | 撤销分油 | 新增入站 `syb.oil.oilCard.cancelShare` → 7.17/7.16 | **不做**。移除该 method、`RedisLock('qyt:cancel:…')`、`QytOil::getVoucherList/adjustVoucher` | | 7.7 入参 | 含 `id_card`、`effective_*`、`institution_config`、`passageway` 动态 | 精简为:`batch_no` / `business_license` / `passageway="1"` / `institution_id` / `waybill_list:[{waybill_no, employee_list:[{mobile, name, quota_amount(分), voucher_name, effective_start:"", effective_end:"", waybill_no_code}]}]` | | DB 字段 | 含 `passageway` / `quota_id` / `poll_times` / `last_poll_time` | 移除以上 4 个;保留 `driver_name` / `batch_no` / `waybill_no` / `waybill_no_code` / `qyt_order_code` / 消费明细 5 项 | | `oil_status_zsy` 取值 | 0/1/2/3/5 | **0 未提交 / 2 发放成功 / 3 发放失败**(无 1 待处理、无 5 撤销) | | `yoshop_qyt_consume` | 含 `quota_id` / `passageway` 列 | 移除该 2 列 | ### 最终文件清单 | 文件 | 状态 | |---|---| | `config/qyt.php` | 精简(去通道切换 / 轮询配置) | | `app/common/crypto/Qyt.php` | 不变(信封 + 7.15 签名 + 验签) | | `app/common/service/QytOil.php` | **精简为 `createAndSendQuota`(7.7) + `h5Url`(7.15)** + `post/curlPost` + 工具 | | `app/console/command/PartnersQueue.php` | 7.7 受理成功=发放成功 → 条件跃迁 0→2 → 回调;含 `reconcile()` 兜底补投 | | `app/console/command/QytPollQueue.php` | **已删除** | | `config/console.php` | 移除 `qyt:poll` 注册 | | `app/api/controller/QytNotify.php` + `public/qytconsume.php` | 不变(7.10 入口,返回 `{"code":"100","msg":"Success"}`) | | `app/console/command/CallbackQueue.php` | `qyt_consume` 分支:`use_status` 条件跃迁 0→1 + `yoshop_qyt_consume` 去重;旧定聚分支保留 | | `app/api/controller/OilCard.php` | `share` 加必填 `name`;`getPayQrCode` → `QytOil::h5Url`;**移除 `cancelShare`**;`saveOrder` 幂等 | | `app/api/service/order/PaySuccess.php` | `shareOil()` 的 `zsy_ticket` 分支 `continue`(小程序停用) | | `app/common/service/QueueService.php` | `migrateDelayedToReady` 改 zrem-first(仅 `notify_queue` 用到延迟队列) | | `qyt_migration.sql` | 精简字段 + 保留 2 个唯一键 | | `慧明宝供应链平台接口文档V1.0.17.docx` | `name` 必填;移除 cancelShare;发放语义改「受理即成功」;无 cancel_share | ### 并发/原子性(最终,简化后) - **`share`**:`uk_partner_saleorder(partners_id, partners_order_no)` 唯一键 + 幂等返回原结果 + `saveOrder` 捕获 Duplicate。 - **`PartnersQueue`**:`RedisLock('qyt:send:{order_id}', 60s)` 串行 + 锁内重读;发放态跃迁 `UPDATE ... WHERE oil_status_zsy=0`,`affected=1` 才回调下单平台;`batch_no` 确定性派生,重试用同一值,靠企油通按 `batch_no` 幂等(`dup_batch_hints` 命中即按已发放);空闲 `reconcile()` 每 60s 补投丢失的 `partners_queue` 消息。 - **`CallbackQueue` 7.10**:`yoshop_qyt_consume` 唯一键去重 + `use_status` 跃迁 `WHERE use_status=0 AND oil_status=1`,`affected=1` 才回调;企油通重推安全。 - **`NotifyQueue`**:原有 3 次退避重试不变;报文结构 `syb.notify.oilCard.change` 不变。 ### 联调前仍需对接人提供 测试/正式域名、`appId`、业务接口 **RSA 拼签字段顺序**、`institution_id`、7.10 回调地址配置方式、7.15 H5 落地页 `appId`;确认 **7.7 支付宝企业码通道响应 `data.status` 语义**(是否 1=受理即发放成功)与 **batch_no 重复提交的返回文案**(校准 `dup_batch_hints`)。 ## 11. 改造方案(基于 0.5 决策,待你对 §10「🔴 待拍板」项给结论后即可开工) ### 11.1 边界原则 - **完全不动**:`mobile-uniapp` 全部;`NotifyQueue` + `PartnersOil` 对下单平台回调的**报文结构**(`syb.notify.oilCard.change`);`yoshop_partners` / `yoshop_partners_goods` 表结构;`app/admin`;`yoshop_merchant` 相关。 - **最小扩展**:`app/api/controller/OilCard.php` 的 `syb.oil.oilCard.share` 仅新增可选入参 `name`。其余入站 method / URL / 加密不变。 - **整体替换**:「我们 → 上游」这一层——删除 `SybOil` / `IdingjuOil` 调用,换 `QytOil`。 - **停用**:小程序油品发放链路(`PaySuccess::shareOil` 油券分支、`Order::qrCode / qrCodeImg`、`Station`)。 ### 11.2 新增 / 改动文件清单(预估) | 类型 | 文件 | 说明 | |---|---|---| | 新增 | `config/qyt.php` | 域名、`appId`、公私钥、`business_license`、`passageway` 默认值、`institution_id`、编号前缀、7.10 回调地址、7.15 落地页地址 | | 新增 | `app/common/crypto/Qyt.php` | 三种签名/验签:①业务信封 ②7.15 H5 签名 ③7.16/7.17 RSA 验签 | | 新增 | `app/common/service/QytOil.php` | `createAndSendQuota(7.7)` / `waybillBatch(7.8)` / `waybillQuotaDetail(7.9)` / `h5Url(7.15)` / `getVoucherList(7.17)` / `adjustVoucher(7.16)` / (可选)`distributable / invoice / enterpriseList` | | 新增 | `public/qytconsume.php` + `app/api/controller/QytNotify.php` | 7.10 消费回调入口,验签,返回 `{"code":"100","msg":"Success"}`,落 `callback_queue`(method `qyt_consume`) | | 新增 | `app/console/command/QytPollQueue.php`(注册 `qyt:poll`) | 退避轮询 7.8 发放结果 | | 新增 | `app/common/library/Amount.php`(或并入 helper) | 元↔分 | | 改 | `app/console/command/PartnersQueue.php` | 换 `QytOil::createAndSendQuota`;受理成功入 `qyt_poll_queue` | | 改 | `app/console/command/CallbackQueue.php` | 删定聚 `oil/use/oil_partners/use_partners` 分支,加 `qyt_consume` 分支 | | 改 | `app/api/controller/OilCard.php` | `share` 加 `name`;`getPayQrCode` → `QytOil::h5Url`;`stock` 数据源改我方 `partners_goods`;**新增 `cancelShare` method**(7.16 减额度) | | 改 | `app/api/service/order/PaySuccess.php` | 移除 `shareOil()` 油券分支(保留优惠券分支) | | 改 | `app/store/controller/partners/Order.php` | `share` 改为「查发放结果(7.8)」;`qrCode` → h5Url;回调按钮走新队列 | | 改 | `app/store/controller/Order.php` | 移除/改造小程序链路 `cancelShare / qrCode / share` | | 改 | `app/api/controller/Station.php`、`app/store/controller/Goods.php` | 停用/摘除上游依赖 | | 删/弃 | `SybOil.php`、`IdingjuOil.php`、`crypto/{Crypto,Idingju}.php`、`config/crypto.php`、`app/api/controller/syb/*`、`public/{oil,oiluse,partnersoil,partnersoiluse}.php` | 确认无引用后移除(可先保留一版做回滚) | | 改 | admin-vue `src/views/partners/order/**`、`src/views/company/**` | 见 11.6 | ### 11.3 数据库改动(全部增量加字段,不改现有字段 / 类型) `yoshop_partners_order` 增加:`driver_name`(司机姓名)、`passageway`(本单通道)、`batch_no`、`waybill_no`、`waybill_no_code`(唯一索引,回调匹配)、`quota_id`(7.17 凭证 ID)、`qyt_order_code`(7.9/7.19 订单号)、`handle_status`(7.8 单条发放态 1/2/3)、`poll_times` / `last_poll_time`、以及消费明细 `station_name / litter / oil_name / pay_fee(分) / consume_time`。 新增表(建议):`yoshop_qyt_consume`(7.10 每笔消费流水)。 > `yoshop_company` / `yoshop_account`:单企业 + 取消用户池后闲置。**不删表**(保历史数据),改为不再写入;`business_license` 等改放 `config/qyt.php`。 ### 11.4 下单平台链路 端到端流程(改造后) ``` 下单平台 POST /partners.php/oilCard/share (method=syb.oil.oilCard.share, RSA信封) body: orgNo, goodsNo, mobile, name(新增), saleOrderNo, oilCardType=zsy_ticket ↓ OilCard.php::share · 校验 appKey→yoshop_partners、requestId 幂等、库存(R-10) · 建 yoshop_partners_order(order_status=10, driver_name=name) · 生成 batch_no / waybill_no / waybill_no_code(企业前缀 + saleOrderNo/order_id) · push partners_queue → 返回 { oilCardNo, amount }(结构不变) ↓ PartnersQueue → QytOil::createAndSendQuota(7.7) params = { batch_no, business_license(配置), passageway(配置, 默认1), institution_id(配置, 通道1必填), waybill_list:[{ waybill_no, waybill_no_code, employee_list:[{ mobile, name, quota_amount(元→分), voucher_name, effective_start:"", effective_end:"" }] }] } · status=1 受理成功 → 记 batch_no, handle_status=1 → push qyt_poll_queue(延迟) · status=2 → oil_status_zsy=3, oil_text=msg ↓ QytPollQueue → QytOil::waybillBatch(7.8) by batch_no(退避轮询) · list[0].handle_status==2 → oil_status=1, oil_status_zsy=2, quota_id → push notify_queue(share_oil) · ==3 → oil_status_zsy=3, oil_text=error_msg · ==1 且未超次数 → 再次延迟入队 ↓ 核销:下单平台 POST /oilCard/getPayQrCode → QytOil::h5Url(7.15) · 返回 { qrCode: }(结构不变;下单平台侧原有「拿字符串生成二维码」逻辑不受影响) ↓ 司机加油后:企油通 POST public/qytconsume.php (7.10) · QytNotify 验签 → 按 waybill_no_code / order_code 命中 order · 写 yoshop_qyt_consume;use_status=1, use_time;返回 {"code":"100","msg":"Success"} · push notify_queue(add_oil) ↓ NotifyQueue(报文结构不变)→ PartnersOil::sendRequest($partners.callback, method=syb.notify.oilCard.change, body={ oilCardNo, amount, shareNo, type, optType }) ``` **`name` 缺失兜底**:下单平台未传时用 `"司机"+mobile后4位` 占位(企业码通道不做姓名实名核验)—— **待你确认是否可接受**。 ### 11.5 对下单平台回调(`syb.notify.oilCard.change`)字段映射(决策 11:不硬凑,按企油通实际返回填) | 回调字段 | 旧值(定聚) | 新值(企油通) | |---|---|---| | `oilCardNo` | `partners_order.oilCardNo` | 不变(我方自生成) | | `amount` | `total_price` | 不变 | | `shareNo` | 定聚 `trade_no` | 发放阶段:留空或填 `waybill_no_code`;消费阶段:填企油通回调的 `order_code`。企油通无对应值时**填空字符串**,不硬造 | | `type` / `optType` | add/sub、share_oil/add_oil/cancel_share | 不变;新增撤销场景 `type=sub, optType=cancel_share` | > 保持报文**结构**与字段名不变(下单平台既有解析不受影响),只是个别字段值可能为空。 ### 11.6 admin-vue 改动(决策 12:满足接口 + 满足运营) - `views/partners/order/Index.vue`:列表增列「批次号 / 运单号 / 发放态 / 通道」;「手动分油」→「查询发放结果(7.8)」;「核销码」→「获取加油链接(7.15)」;增「撤销分油(7.16)」「加油明细(7.9)」。 - 新增「企业管理」页:企业对接参数 + 通道切换(1/2) + `institution_id` + 企业信息(7.5/7.6) + 企业余额(7.11) + 发票下载(7.14) + 消费流水查询。 - 订单详情页兼容「旧定聚字段 + 新企油通字段」两种展示。 - 旧「分油公司 / 分油用户」菜单:保留只读(历史数据),不再新增。 ### 11.7 建议实施顺序 **A. 不依赖对接人环境料,可先做(脚手架 + 内部改造):** 1. DB 迁移脚本(`yoshop_partners_order` 加字段 + 新建 `yoshop_qyt_consume`)。 2. `config/qyt.php`(占位)+ `app/common/library` 单位/编号 helper。 3. `app/common/crypto/Qyt.php`(信封结构 + 7.15 算法已文档化可实现;业务接口拼签字段顺序留 TODO 待确认)。 4. `app/common/service/QytOil.php`(各接口入参组装 + 调用骨架)。 5. 改 `app/api/controller/OilCard.php`:`share` 加 `name`;新增 `cancelShare` method;`stock` 改内部数据源。 6. 改 `PartnersQueue` + 新增 `QytPollQueue`(`qyt:poll`) + `QytNotify` + `public/qytconsume.php` + 改 `CallbackQueue`。 7. 停用小程序油品链路(`PaySuccess::shareOil` 油券分支、`Order::qrCode/qrCodeImg`、`Station`、`store/Goods::stock`)。 8. admin-vue:`views/partners/order/**` + 新增「企业管理」页。 **B. 拿到对接人环境料后(R-19/R-20):** 9. 填 `config/qyt.php` 真值 + 补 `Qyt.php` 拼签字段顺序 + 7.16 凭证定位方式。 10. 测试环境联调:7.7 → 7.8 → 7.15 → 7.10(用 7.23 模拟消费)→ 7.16 撤销。 11. 全链路回归(下单→发放→轮询→核销→消费回调→回调下单平台→撤销)+ 旧数据展示。 **C. 收尾:** 12. 确认无引用后清理 `SybOil` / `IdingjuOil` / `crypto/{Crypto,Idingju}` / `config/crypto.php` / `app/api/controller/syb/*` / 旧入口文件。 --- ## 附:本阶段已核查的关键文件清单 - 后端上游对接:`app/common/service/{SybOil,IdingjuOil,PartnersOil}.php`、`app/common/crypto/{Crypto,Idingju,RsaUtil}.php`、`config/{crypto,rsa}.php` - 入站 API:`app/api/controller/OilCard.php`、`app/api/controller/SybNotify.php`、`app/api/controller/syb/*`、`app/api/controller/Station.php` - 队列:`app/console/command/{CallbackQueue,PartnersQueue,NotifyQueue}.php`、`config/console.php`、`app/common/service/QueueService.php` - 订单:`app/api/controller/Order.php`、`app/api/service/order/PaySuccess.php`、`app/api/service/main/order/PaySuccess.php`、`app/api/model/Order.php`、`app/api/model/partners/Order.php`、`app/common/model/partners/Order.php` - 后台:`app/store/controller/{Order,Company,Partners}.php`、`app/store/controller/partners/Order.php`、`app/store/model/{Company,Partners}.php`、`app/common/enum/order/*` - 入口:`public/{partners,partnersoil,partnersoiluse,oil,oiluse}.php` - admin-vue:`src/config/router.config.js`、`src/api/{partners,company,order}/*`、`src/views/{company,partners,order,account}/**` - mobile-uniapp:`config.js`、`api/{station,order,card,goods,checkout}.js` - 数据库:`oil.sql` 中 `yoshop_{account,company,company_balance_log,partners,partners_goods,partners_order,order,order_goods,order_qrcode,order_record,request_log,merchant}` 建表与样例数据 - 文档:`企油通接口对接文档.md`(第 7 章 23 接口)、`慧明宝供应链平台接口文档V1.0.16.docx`(= 我们对下单平台的入站契约) --- ## 附 G. 后台功能适配 + 接口文档就地修订(2026-09-04) ### G1. 后台(app/store + admin-vue)适配 **下单平台订单管理**(运营日常用的「查看订单 / 处理订单」) | 层 | 文件 | 改动 | |---|---|---| | 后端 | `app/store/controller/partners/Order.php` | **整体重写**。移除 `IdingjuOil` / `CompanyModel` / `getCompany()` 硬编码;`qrCode()` 改调 `QytOil::h5Url`(7.15);`share()` 改为「重新发放」——仅允许 `oil_status_zsy=3(发放失败)` 条件重置为 0 后重投 `partners_queue`(避免与在途单冲突);新增 `detail()` 返回订单 + `yoshop_qyt_consume` 加油流水;`oilCallback()/useCallback()` 保留为「重推结果给下单平台」并加状态前置校验 | | 后端 | `app/store/model/partners/Order.php` | `getFilter()` 新增检索:司机姓名 `driver_name`、单号 `orderNo`(油卡编号/销售单号/批次号/运单号 模糊)、企油通发放态 `oil_status_zsy` | | 前端 | `views/partners/order/Index.vue` | 搜索区加「司机姓名 / 单号 / 企油通发放态」,「用户电话」改「司机手机号」;列表新增「企油通单号(批次/运单)」「司机(姓名+手机)」「加油信息(油站/油品/升数/实付)」列,去掉旧「分油记录编号」列;状态列增加企油通发放态标签 + `oil_text` 失败原因;按钮文案改为 重新发放 / 加油链接 / 重推发放结果 / 重推加油结果 | | 前端 | `views/partners/order/modules/PayForm.vue` | **重写**:原来把二维码串塞 `