83 KiB
企油通对接现状分析报告(第一阶段:项目理解与代码调研)
版本: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:queuecallback_queue处理上游回调(method: oil/use/oil_partners/use_partners)partners:queuepartners_queue下单平台订单入队后 → 调用上游发放 notify:queuenotify_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-tp6api应用。 -
标准 yoshop 商城客户端(商品 / 购物车 / 结算 / 订单 / 微信支付 / 售后)。
-
仅两处直接触达「油品」语义(其余全部是服务端在支付成功后自动处理):
api 文件 接口 服务端 依赖上游? api/station.jsstation/listapi/controller/Station.php→SybOil::baseGasStationList是(且当前已坏,见风险) api/order.jsorder/qrCode、order/qrCodeImgapi/controller/Order.php→IdingjuOil::payQrCodeRequest是(核销码/图) api/order.jsorder/list、order/detail、order/cancel、order/pay…标准商城订单 否(间接) order/qrCodeImg出参是{ base64: "data:image/png;base64,..." },服务端通过shell_exec("node public/myscript.js <url>")把上游返回的二维码链接转成图片。这是企油通改造的强约束点(企油通给的是 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_companyIdingjuOil::oilOilCardShare(...),notify_url=partnersoil.php、use_notify_url=partnersoiluse.php- 回写
shareNo / qrCode / oil_status_zsy / oil_status;若state==2→ pushnotify_queue(optType=share_oil)
上游回调(上游 → 我们):
public/partnersoil.php→/sybNotify/partnersNotify(method 置为oil_partners)→callback_queuepublic/partnersoiluse.php→/sybNotify/partnersUse(method 置为use_partners)→callback_queueCallbackQueuecaseoil_partners:按shareNo命中yoshop_partners_order,useStatus=='1'→oil_status=1 / qrCode,pushnotify_queue(share_oil)CallbackQueuecaseuse_partners:写yoshop_order_record,useStatus=='2'→use_status=1 / use_time,pushnotify_queue(add_oil)
出站回调(我们 → 下单平台):app/console/command/NotifyQueue.php 消费 notify_queue:
- 取
yoshop_partners_order+yoshop_partners PartnersOil::sendRequest($partners['callback'], ...),headermethod='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/*_partnersPaySuccess::shareOil的SybOil版本被注释,改用IdingjuOilyoshop_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 PowerShellGet-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消息。CallbackQueue7.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: <H5免登URL> }(结构不变;下单平台侧原有「拿字符串生成二维码」逻辑不受影响)
↓ 司机加油后:企油通 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. 不依赖对接人环境料,可先做(脚手架 + 内部改造):
- DB 迁移脚本(
yoshop_partners_order加字段 + 新建yoshop_qyt_consume)。 config/qyt.php(占位)+app/common/library单位/编号 helper。app/common/crypto/Qyt.php(信封结构 + 7.15 算法已文档化可实现;业务接口拼签字段顺序留 TODO 待确认)。app/common/service/QytOil.php(各接口入参组装 + 调用骨架)。- 改
app/api/controller/OilCard.php:share加name;新增cancelSharemethod;stock改内部数据源。 - 改
PartnersQueue+ 新增QytPollQueue(qyt:poll) +QytNotify+public/qytconsume.php+ 改CallbackQueue。 - 停用小程序油品链路(
PaySuccess::shareOil油券分支、Order::qrCode/qrCodeImg、Station、store/Goods::stock)。 - 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 |
重写:原来把二维码串塞 <iframe>,现改为用 vue-qr 渲染 7.15 H5 免登地址二维码 + 只读链接框 + 一键复制(运营可直接把链接发给司机) |
| 前端 | modules/{ShareForm,OilForm,UseForm}.vue、api/partners/order.js |
标题与注释文案同步 |
views/partners/**(合作商列表/新增/编辑/对接参数/余额)维护的是下游接口账户(orgNo / appKey / RSA 公私钥 / 回调地址 / 可售商品与额度),与上游换成企油通无关,无需改动;其中「商品额度」正是/oilCard/stock现在的数据来源。
停用旧上游依赖的后台/小程序端点(上游定聚、智慧油客已下线,这些接口再调只会超时或报错,统一改为明确提示,页面仍可查历史数据)
| 文件 | 方法 | 处理 |
|---|---|---|
app/api/controller/Order.php |
qrCode() / qrCodeImg() |
返回「该功能已停用」(小程序不改代码,只是拿到提示) |
app/api/controller/Station.php |
list() |
返回空列表(企油通无油站查询能力),小程序页面不报错 |
app/store/controller/Order.php |
share() / cancelShare() / qrCode() |
返回「小程序油品链路已停用」(顺带修掉了原先调用未定义方法的致命错误) |
app/store/controller/Company.php |
stock() |
返回「上游库存同步已停用」 |
app/store/controller/Goods.php |
onReloadStock() |
同上 |
app/store/controller/User.php |
add() / oil() |
分油用户池已停用,不再向上游注册用户 / 手动分油 |
其余
new SybOil()残留经核对均只用于写日志(saveLogStore),无业务副作用;PaySuccess::shareOil内的IdingjuOil调用位于已continue的分支,不可达。
G2. 接口文档就地修订(不加变更说明章节)
慧明宝供应链平台接口文档V1.0.17.docx 直接在原文覆盖修改,未新增任何「变更说明 / 附录」章节,并删除本期无用的接口与参数。
版本 / 接口层面
| # | 位置 | 改动 |
|---|---|---|
| 1 | 1.2 版本号 | V1.0.16 → V1.0.17 |
| 2 | 3.4 基础数据查询 / 油站列表查询 | 整章删除(企油通无油站查询能力;含请求应答表与报文示例,约 277KB) |
| 3 | 2.7 接口清单列表 | 删「油站查询」行;序号 5→4;付款码申请用途改为「获取司机免登加油地址(H5)」 |
| 4 | 目录 | 删除对应两条 TOC 条目 |
最终对外接口收敛为 4 个:syb.oil.oilCard.share / syb.oil.oilCard.shareList / syb.pay.qrCode.request / syb.notify.oilCard.change(另有正文中的 stockList、orderStatus 两个查询接口)。
参数层面(去掉本期无用的传参)
| 接口 | 删除 / 修改 |
|---|---|
syb.oil.oilCard.share |
删请求体 amount(金额由 goodsNo 面额决定,本期不传);新增必填 name(司机姓名 V50);goodsNo 约束 ?→1;使用场景⑵ 改为「同步返回受理结果,发放结果由油卡变动通知推送(optType=share_oil)或用订单状态查询主动查」;请求报文示例同步删 amount 与注释行、补 "name" |
syb.pay.qrCode.request |
删请求体 longitude / latitude / oilCardType 三个参数(企油通 H5 免登不需要);API 描述改为「获取司机免登加油地址(H5)」;使用场景改写;返回值 qrCode 描述由「二维码链接」改为「H5免登加油地址」并去掉「2分钟有效/扫一次失效」旧口径;请求与应答报文示例同步更新(应答示例换成企油通 H5 地址样例) |
syb.oil.oilCard.stockList |
使用场景改为「查询自身可下单额度与用量统计(平台内部额度,非上游实时库存)」 |
syb.oil.oilCard.shareList |
返回字段 num 口径由「分油数量(升)」修正为「购买数量(张)」,与实现一致 |
syb.notify.oilCard.change |
optType 删除未使用的 发券:share_volume,仅保留 share_oil / add_oil |
校验:XML 良构 ✓、XSD validate.py 全部通过 ✓、段落 1717 → 1392、残留检查 gasStation/油站/share_volume/二维码链接/longitude/latitude/「变更说明」均为 0。
仍未做:本机无 LibreOffice,无法渲染 PDF 目视核对排版;删章后小节序号由 Word 样式自动重排,打开时建议「更新域」刷新目录。
附 H. 下单改为按金额直传(2026-09-06)
下单平台不再传 goodsNo(商品编码),改为直接传 amount(金额,元)。商品/面额概念从下单链路整体移除。
后端
| 文件 | 改动 |
|---|---|
app/api/controller/OilCard.php |
share() 入参 goodsNo → amount(必填,正则校验:元、≤2 位小数、>0);删除商品查找、goods_sku 平台库存校验、partners_goods 合作商额度校验、下单扣库存;落单金额三字段(goods_price/total_price/total_pay_price)统一取 amount;返回 amount 用传入值 |
| 同上 | 删除整个 stock() 方法(syb.oil.oilCard.stockList 完全建立在 goodsNo 之上,已无意义);删除已失效的 updateGoodsStockNum()、getCompany();清理 6 个不再使用的 use |
| 同上 | shareList 响应去 productName;orderStatus 响应去 province / goods_name / goods_no(这些字段现在恒为空) |
app/api/model/partners/Order.php |
saveOrder() 去掉 PartnersGoods 的 setIncUseNum / setDecStockNum,事务包装随之取消(单条写入无需事务) |
app/store/model/partners/Order.php |
列表查询去掉 goods.images.file 关联与 goods_no 检索项 |
前端 admin-vue
views/partners/order/Index.vue:删除「商品编码」搜索项、「商品信息」列与 GoodsItem 组件引用;列名「油卡数量/油卡金额」→「数量/发放金额」,汇总文案→「发放总金额」。eslint 0 error(warning 数与改动前一致)。
接口文档(就地修订,无变更说明章节)
| 位置 | 改动 |
|---|---|
| 3.2.1 用户分油 请求体 | 删 goodsNo,新增 amount(必填,String V13,「本单发放给司机的金额,单位元,最多两位小数且必须大于 0」);请求示例同步 |
油券库存查询 syb.oil.oilCard.stockList |
整节删除 + 目录条目删除 |
| 分油记录查询 | 响应删 productName 字段与示例行 |
| 订单状态查询 | 响应删 province / goods_name 字段行;两处 JSON 示例删对应 3 行;oil_status_zsy 描述由「中石油下单状态 1待处理/2已发券/3发券失败」改为「发放状态:0未提交 / 2发放成功 / 3发放失败」 |
校验:XML 良构 ✓、XSD 全过 ✓、段落 1717 → 1234;残留检查 goodsNo/stockList/油券库存/productName/goods_name/goods_no/province/中石油 均为 0。
最终 share 请求体仅剩 6 个参数:orgNo / amount / mobile / name / saleOrderNo / oilCardType。
额度管控:改用合作商余额(已实现)
去掉 goodsNo 后,原先由 yoshop_partners_goods.stock_num 承担的下单额度管控,改由 yoshop_partners.balance(合作商余额) 承担。
新增 app/common/service/PartnersBalance.php:
| 方法 | 说明 |
|---|---|
deduct() |
原子扣减:UPDATE yoshop_partners SET balance = balance - amt WHERE partners_id=? AND balance >= amt,affected=1 才算成功 —— 天然防并发超扣。成功返回流水ID |
refund() |
回补余额并写退款流水 |
bindOrder() |
建单后把 order_id 回填到扣款流水(deduct 时还没有订单ID) |
balance() |
查询当前余额 |
流水写入 yoshop_partners_balance_log,场景沿用现有枚举:扣减 = CONSUME(20),回补 = REFUND(40);金额拼接前用 number_format 规范化,避免注入。
接入点
| 位置 | 行为 |
|---|---|
OilCard::share |
幂等检查通过后才扣款(重复 saleOrderNo 直接返回原单,不重复扣);扣款失败 → 2028 账户余额不足;建单抛异常或未成功 → 立即回补;建单成功 → bindOrder 回填订单ID |
PartnersQueue |
三条发放失败路径(缺司机信息 / 7.7 调用失败 / data.status=2)在状态条件跃迁 affected=1 时回补余额,天然幂等 |
store/controller/partners/Order::share(后台重新发放) |
失败时余额已回补,重发前重新扣减;若状态被其它进程改变导致重置失败 → 回补刚扣的金额 |
资金一致性:先扣后建单、失败即回补;所有回补都挂在「条件跃迁胜出」之后,重复消息 / 多进程不会重复回补。
文档:amount 字段取值说明补充「下单时平台校验并扣减对接公司账户余额,余额不足返回错误码 2028;发放失败时该笔金额原路回补」。错误码 2028 账户余额不足 原本就在附录 4.2 中,无需新增。
运营入口:后台「合作商管理 → 充值」已可维护余额,「合作商 → 余额明细」可查流水,无需新增页面。
合作商「可售商品 + 库存」下线(已清理)
额度改由余额承担后,yoshop_partners_goods / yoshop_partners_stock_log 已无任何读写方,整体移除。
删除的文件(5 个 PHP + 1 个 Vue)
app/api/model/PartnersGoods.php、app/common/model/PartnersGoods.php、app/store/model/PartnersGoods.php、app/common/model/partners/StockLog.php、app/store/model/partners/StockLog.php、admin-vue/src/views/partners/modules/MultiGoods.vue
改动的文件
| 文件 | 改动 |
|---|---|
app/store/model/Partners.php |
add() / edit() 去掉 checkGoodsData、PartnersGoodsModel::increased/updates、StockLogModel::increased 及两个 import |
app/store/controller/Partners.php |
detail() 不再返回 goodsList(连同 allot_num 填充逻辑),去 import |
admin-vue/views/partners/{Create,Update}.vue |
移除 <MultiGoods> 组件、goodsList data、提交时的 values.goodsList、handleGoodsChange、import 与 components 注册 |
admin-vue/views/partners/modules/index.js |
移除 MultiGoods 导入导出 |
admin-vue/common/model/partners/Index.js |
移除 GoodsApi import、formData.goods、getGoodsList() 方法及其在 getFromData 中的调用 |
数据库:qyt_migration.sql 第 4 节把两张表注释标记为「已下线,仅历史数据」,并附上 DROP TABLE 语句(已注释)。两表仍有历史数据,是否物理删除由你决定,确认后取消注释执行即可。
校验:PHP 端 PartnersGoods / StockLog / partners_goods / partners_stock_log 全仓残留 0;admin-vue MultiGoods / goodsList 残留 0,eslint 0 problems。
附 I. 后台「分油公司 / 分油用户」菜单下线(2026-09-06)
企油通改为单企业配置(config/qyt.php)、分油用户池取消后,这两个菜单对应的 yoshop_company / yoshop_account 已无业务意义,后端接口也早已返回「已停用」。本次把前端入口整体收掉。
删除
| 类型 | 路径 |
|---|---|
| 页面 | views/company/(Index / Create / Update / balance / modules 共 8 个文件 + style.less)、views/account/Index.vue |
| API | api/company/{index,balance,recharge}.js、api/account/index.js |
| 模型 / 枚举 | common/model/company/Index.js、common/enum/company/**(3 个) |
| 用户分油弹窗 | views/user/modules/OilForm.vue(依赖已停用的 /user/oil) |
改动
| 文件 | 改动 |
|---|---|
config/router.config.js |
移除整个 /company 路由块(含嵌套的 /account),菜单「分油公司」「分油用户」「公司余额明细」一并消失 |
common/model/user/Index.js |
去 CompanyApi import、formData.companyList、getCompanyList() 及其在 getFromData 的调用 |
views/user/{Create,Update}.vue |
移除表单里的「分油公司」下拉(数据源已不存在) |
views/user/Index.vue |
移除 OilForm 组件、import、注册、handleOil() 与那行已注释的「分油」按钮 |
views/user/modules/index.js |
移除 OilForm 导入导出 |
api/user/index.js |
移除 oil: '/user/oil' 与 oil() 方法 |
校验
- 残留引用检查:
views/company/api/company/model/company/enum/company/views/account/Index/api/account均为 0;OilForm仅剩合作商订单页那个(不同文件,需保留)。 - eslint:本次改动引入 0 新错误。改动过程中在
views/partners/{Create,Update}.vue留下的 3 处comma-dangle已修复。当前全量仅剩 2 个改动前就存在的错误:config/router.config.js的comma-dangle、views/user/grade/modules/index.js的eol-last(两者均未被本次改动触碰)。
后端未动(说明)
app/store/controller/{Company,Account,User}.php 及 yoshop_company / yoshop_account 的模型仍在仓库中,相关方法已返回「已停用」提示,现在没有任何前端调用方。保留是为了不影响历史数据查询与可能的权限表(yoshop_store_api / yoshop_store_menu)记录;如需彻底清除,可在确认权限表无关联后单独处理。