第二次更新

This commit is contained in:
2026-09-10 20:56:46 +08:00
parent 4d6a7e7aac
commit caeb4d6760
310 changed files with 2427 additions and 382 deletions
+167 -13
View File
@@ -6,11 +6,13 @@
* 放在 public/ 下,浏览器访问:http://你的域名/qyt_test.php
* 也可命令行:php qyt_test.php share
*
* 它做四件事:
* 它做五件事:
* 1) 从数据库读取合作商(appKey / RSA 私钥 / orgNo)
* 2) 按「慧明宝」规范组装 RSA+AES 信封并调用我方入站接口
* 3) 展示明文请求 / 待签串 / 密文报文 / 服务端响应
* 4) act=notify_receiver 作为回调接收端,解密+验签我方推送的
* 2) 展示本次下单会用哪个【企油通企业】及其支付通道(口径同后端:
* 合作商绑定的企业 -> 默认企业),含是否要求身份证号、机构号是否已配置
* 3) 按「慧明宝」规范组装 RSA+AES 信封并调用我方入站接口
* 4) 展示明文请求 / 待签串 / 密文报文 / 服务端响应
* 5) act=notify_receiver 作为回调接收端,解密+验签我方推送的
* syb.notify.oilCard.change,并返回 {"code":"00"}
*
* ⚠️ 仅用于联调,正式环境请删除本文件。
@@ -70,6 +72,87 @@ function getPartner($root, $appKey)
return $row;
}
/**
* 解析某个合作商下单时实际使用的企油通企业与通道。
* 口径与 app\common\model\qyt\Enterprise::resolve 一致:
* 合作商绑定的企业 -> 默认企业(is_default=1 且启用)
* 接入方级参数(域名 / appId / 密钥)仍取 .env 的 [QYT] 段与后台设置。
* 本脚本是独立入口、不加载 ThinkPHP,所以重新实现了一遍,改动时两边要同步。
*/
function qytConf($root, $partner)
{
static $conf = null;
if ($conf !== null) {
return $conf;
}
$ini = parse_ini_file($root . '/.env', true, INI_SCANNER_RAW) ?: [];
$q = isset($ini['QYT']) ? $ini['QYT'] : [];
$get = function ($k, $d = '') use ($q) {
return isset($q[$k]) && trim((string)$q[$k]) !== '' ? trim((string)$q[$k]) : $d;
};
$conf = [
'base_url' => $get('BASE_URL'),
'no_prefix' => $get('NO_PREFIX', 'HM'),
'source' => '.env',
'enterprise' => null,
];
// 后台「企油通对接设置」覆盖接入方级默认值
try {
$st = db($root)->prepare("SELECT `values` FROM yoshop_store_setting WHERE `key`='qyt' ORDER BY store_id ASC LIMIT 1");
$st->execute();
$json = $st->fetchColumn();
$row = $json ? json_decode($json, true) : null;
if (is_array($row)) {
$conf['source'] = '.env + 后台设置';
foreach (['base_url', 'no_prefix'] as $k) {
if (isset($row[$k]) && trim((string)$row[$k]) !== '') {
$conf[$k] = trim((string)$row[$k]);
}
}
}
} catch (Throwable $e) {
// 忽略
}
// 企业:合作商绑定的 -> 默认企业
try {
$pdo = db($root);
$ent = null;
$bind = (int)(isset($partner['qyt_enterprise_id']) ? $partner['qyt_enterprise_id'] : 0);
if ($bind > 0) {
$st = $pdo->prepare('SELECT * FROM yoshop_qyt_enterprise WHERE enterprise_id = ? AND is_enable = 1 LIMIT 1');
$st->execute([$bind]);
$ent = $st->fetch() ?: null;
}
if (!$ent) {
$st = $pdo->query('SELECT * FROM yoshop_qyt_enterprise WHERE is_enable = 1 AND is_default = 1 ORDER BY enterprise_id ASC LIMIT 1');
$ent = $st->fetch() ?: null;
$conf['from_default'] = (bool)$ent;
} else {
$conf['from_default'] = false;
}
if ($ent) {
$pw = isset($ent['passageway']) && $ent['passageway'] === 'pingan' ? 'pingan' : 'alipay';
$ent['passageway'] = $pw;
$ent['passageway_code'] = $pw === 'pingan' ? 2 : 1;
$ent['passageway_name'] = $pw === 'pingan' ? '平安银行' : '支付宝企业码';
$ent['require_id_card'] = $pw === 'pingan';
// 企业可覆盖编号前缀
if (trim((string)$ent['no_prefix']) !== '') {
$conf['no_prefix'] = trim((string)$ent['no_prefix']);
}
$conf['enterprise'] = $ent;
}
} catch (Throwable $e) {
$conf['enterprise_error'] = $e->getMessage();
}
return $conf;
}
/** 平台公钥:加密 AES 密钥 / 验签我方回调 */
function platformPublicKey($root)
{
@@ -234,17 +317,23 @@ function defaultBody($act, $orgNo)
$mobile = isset($_GET['mobile']) ? $_GET['mobile'] : '13800000001';
if ($act === 'share') {
$body = [
'orgNo' => $orgNo,
'amount' => isset($_GET['amount']) ? $_GET['amount'] : '100.00',
'mobile' => $mobile,
'name' => isset($_GET['name']) ? $_GET['name'] : '张三',
'saleOrderNo' => $saleOrderNo,
'oilCardType' => 'zsy_ticket',
];
// 司机身份证号:平安银行通道必传,支付宝企业码通道可不传。
// 加 &noIdCard=1 可故意不传,用来验证实名通道下的 0001 拒单是否生效。
if (empty($_GET['noIdCard'])) {
$body['idCard'] = isset($_GET['idCard']) ? $_GET['idCard'] : '450103199001011238';
}
return [
'method' => 'syb.oil.oilCard.share',
'path' => '/oilCard/share',
'body' => [
'orgNo' => $orgNo,
'amount' => isset($_GET['amount']) ? $_GET['amount'] : '100.00',
'mobile' => $mobile,
'name' => isset($_GET['name']) ? $_GET['name'] : '张三',
'saleOrderNo' => $saleOrderNo,
'oilCardType' => 'zsy_ticket',
],
'body' => $body,
];
}
if ($act === 'qrcode') {
@@ -285,6 +374,7 @@ $act = isset($_GET['act']) ? $_GET['act'] : (isset($argv[1]) ? $argv[1] : '')
$fatal = '';
$result = null;
$partner = null;
$qconf = null;
try {
if ($act === 'notify_receiver') {
@@ -292,6 +382,7 @@ try {
}
$partner = getPartner($ROOT, TEST_APPKEY);
$platformPub = platformPublicKey($ROOT);
$qconf = qytConf($ROOT, $partner);
if (in_array($act, ['share', 'qrcode', 'status', 'sharelist'], true)) {
$def = defaultBody($act, $partner['orgNo']);
@@ -310,6 +401,22 @@ if (PHP_SAPI === 'cli') {
echo '错误:' . $fatal . "\n";
exit(1);
}
$ent = $qconf['enterprise'];
if (!$ent) {
echo "当前企业:【未匹配到可用企业】请先在后台「设置 -> 企业管理」新建企业并设为默认,否则下单会被拒绝
";
} else {
echo '当前企业:' . $ent['company_name'] . '(' . $ent['business_license'] . ')'
. ($qconf['from_default'] ? ' [默认企业]' : ' [合作商绑定]') . "
";
echo '当前通道:' . $ent['passageway_name'] . '(passageway=' . $ent['passageway_code'] . ')'
. ' 身份证号' . ($ent['require_id_card'] ? '必传' : '可不传')
. ' 机构号' . ($ent['institution_id'] !== '' ? '已配置' : '【未配置,下发必失败】')
. ' 企业状态' . $ent['status'] . "
";
echo '编号前缀:' . $qconf['no_prefix'] . ' 接入方配置来源:' . $qconf['source'] . "
";
}
if (!$result) {
echo "用法:php qyt_test.php [share|qrcode|status|sharelist]\n";
exit;
@@ -345,6 +452,7 @@ $curOil = isset($_GET['oilCardNo']) ? $_GET['oilCardNo'] : '';
.btns a{display:inline-block;margin:0 8px 8px 0;padding:7px 16px;background:#1890ff;color:#fff;
border-radius:4px;text-decoration:none;font-size:13px}
.btns a.g{background:#52c41a}.btns a.o{background:#faad14}.btns a.p{background:#722ed1}
.btns a.r{background:#ff4d4f}
table{border-collapse:collapse;width:100%;font-size:13px}
th,td{border:1px solid #eee;padding:6px 10px;text-align:left;vertical-align:top;word-break:break-all}
th{background:#fafafa;width:150px;font-weight:600;color:#555}
@@ -375,6 +483,48 @@ $curOil = isset($_GET['oilCardNo']) ? $_GET['oilCardNo'] : '';
</table>
</div>
<?php $ent = $qconf['enterprise']; ?>
<div class="card">
<h2>本次下单使用的企业与通道</h2>
<?php if (!$ent): ?>
<p class="err">未匹配到可用企业。请先到后台「设置 &rarr; 企业管理」新建企业并设为默认,否则下单接口会直接拒绝。</p>
<?php if (!empty($qconf['enterprise_error'])): ?>
<p class="err">读取企业表出错:<?php echo htmlspecialchars($qconf['enterprise_error']); ?></p>
<?php endif; ?>
<?php else: ?>
<table>
<tr><th>企业</th><td>
<b><?php echo htmlspecialchars($ent['company_name']); ?></b>
<?php echo $qconf['from_default'] ? '(来自<b>默认企业</b>兜底)' : '(该合作商<b>已绑定</b>此企业)'; ?>
</td></tr>
<tr><th>统一社会信用代码</th><td><?php echo htmlspecialchars($ent['business_license']); ?></td></tr>
<tr><th>企业状态</th><td>
<?php if ($ent['status'] === 'approved'): ?><span class="ok">审核通过</span>
<?php else: ?><span class="err"><?php echo htmlspecialchars($ent['status']); ?></span> 未通过审核时 7.15 免登地址会报「企业尚未通过审核」
<?php endif; ?>
</td></tr>
<tr><th>支付通道</th><td>
<b><?php echo htmlspecialchars($ent['passageway_name']); ?></b>(passageway=<?php echo (int)$ent['passageway_code']; ?>)
</td></tr>
<tr><th>司机身份证号</th><td>
<?php if ($ent['require_id_card']): ?>
<span class="err">必传</span> 该通道要求实名,下单不传 idCard 会返回 0001 拒单
<?php else: ?>
<span class="ok">可不传</span> 该通道不要求实名,传了也不会上送给企油通
<?php endif; ?>
</td></tr>
<tr><th>机构号</th><td>
<?php if ($ent['institution_id'] !== ''): ?><span class="ok">已配置</span>
<?php elseif ((int)$ent['passageway_code'] === 1): ?><span class="err">未配置</span> 支付宝企业码通道必填,下发时会失败并原路退回余额
<?php else: ?><span class="ok">平安通道无需机构号</span>
<?php endif; ?>
</td></tr>
<tr><th>编号前缀</th><td><?php echo htmlspecialchars($qconf['no_prefix']); ?></td></tr>
<tr><th>企油通域名</th><td><?php echo $qconf['base_url'] !== '' ? htmlspecialchars($qconf['base_url']) : '<span class="err">未配置</span>'; ?> <span class="sub">来源:<?php echo htmlspecialchars($qconf['source']); ?></span></td></tr>
</table>
<?php endif; ?>
</div>
<div class="tip">
接口地址默认取当前域名;如需指定,链接后加 <code>&amp;api=http://你的域名</code>。<br>
<b>下单前提</b>:三个队列进程已启动(partners:queue / callback:queue / notify:queue)、Redis 可用、合作商余额充足。
@@ -387,10 +537,14 @@ $curOil = isset($_GET['oilCardNo']) ? $_GET['oilCardNo'] : '';
<a class="o" href="?act=qrcode&amp;oilCardNo=<?php echo urlencode($curOil); ?>">② 获取加油链接 (qrCode)</a>
<a class="p" href="?act=status&amp;oilCardNo=<?php echo urlencode($curOil); ?>">③ 订单状态 (orderStatus)</a>
<a href="?act=sharelist">④ 分油记录 (shareList)</a>
<a class="r" href="?act=share&amp;noIdCard=1">⑤ 下单但不传身份证号</a>
</div>
<div class="sub" style="margin:6px 0 0">
②③ 需要 oilCardNo:先点①拿到后会自动带上。<br>
① 可自定义参数:<code>?act=share&amp;amount=50.00&amp;mobile=13800000002&amp;name=李四</code>
① 可自定义参数:<code>?act=share&amp;amount=50.00&amp;mobile=13800000002&amp;name=李四&amp;idCard=110101199003071233</code><br>
⑤ 用来验证实名校验:<?php echo !$ent ? '当前无可用企业' : ($ent['require_id_card']
? '当前是<b>' . htmlspecialchars($ent['passageway_name']) . '</b>通道,应当返回 <b>0001</b> 拒单'
: '当前是<b>' . htmlspecialchars($ent['passageway_name']) . '</b>通道,不要求实名,应当<b>正常下单成功</b>'); ?>
</div>
</div>