1、合作商余额查询

2、分油账户司机可用额度
This commit is contained in:
2026-10-08 23:12:33 +08:00
parent ae94c1dc00
commit 45452c1799
32 changed files with 2024 additions and 6 deletions
+199
View File
@@ -0,0 +1,199 @@
<?php
// +----------------------------------------------------------------------
// | 模拟企油通 7.10「运单加油明细推送」 —— 联调 / 补推用(CLI)
// +----------------------------------------------------------------------
// | 按企油通的真实口径推送:multipart/form-data,业务参数放在表单字段 params 里。
// |
// | 用法(在站点根目录执行):
// | php deploy/qyt_consume_push.php --order=6 --amount=100
// | php deploy/qyt_consume_push.php --code=HMCTEST20260914233556192 --amount=100
// | php deploy/qyt_consume_push.php --order=6 --amount=30 --dry-run # 只打印报文不发送
// |
// | 常用参数:
// | --order=订单ID 从数据库取运单号等信息(推荐)
// | --code=运单唯一流水 不查库直接指定 waybill_no_code
// | --amount=金额(元) 本次加油占用金额,默认取订单剩余未加油金额
// | --order-code=消费单号 去重键,默认自动生成;想测【重复推送】就填上次用过的
// | --station=加油站名 默认「模拟加油站」
// | --url=回调地址 默认取 .env 的 QYT.CONSUME_NOTIFY_URL
// | --dry-run 只打印,不实际发送
// |
// | ⚠️ 这会写入真实的加油流水、累计订单已加油金额、并触发给下单平台的加油通知,
// | 只用于联调环境。联调结束请删除本文件。
// +----------------------------------------------------------------------
declare (strict_types=1);
if (PHP_SAPI !== 'cli') {
http_response_code(403);
exit('仅限命令行执行');
}
$root = dirname(__DIR__);
// ---------------- 参数解析 ----------------
$opt = [];
foreach (array_slice($argv, 1) as $arg) {
if (preg_match('/^--([a-zA-Z0-9\-_]+)(?:=(.*))?$/', $arg, $m)) {
$opt[str_replace('-', '_', $m[1])] = $m[2] ?? '1';
}
}
$orderId = isset($opt['order']) ? (int) $opt['order'] : 0;
$code = isset($opt['code']) ? trim((string) $opt['code']) : '';
$dryRun = !empty($opt['dry_run']);
$station = isset($opt['station']) ? (string) $opt['station'] : '模拟加油站';
$orderCode = isset($opt['order_code']) ? trim((string) $opt['order_code']) : '';
if ($orderId <= 0 && $code === '') {
exit("用法:php deploy/qyt_consume_push.php --order=<订单ID> [--amount=金额] [--dry-run]\n"
. " php deploy/qyt_consume_push.php --code=<运单唯一流水> --amount=金额\n"
. "详细参数见本文件头部注释。\n");
}
// ---------------- 读取 .env ----------------
$ini = @parse_ini_file($root . '/.env', true, INI_SCANNER_RAW) ?: [];
$db = $ini['DATABASE'] ?? [];
$qyt = $ini['QYT'] ?? [];
$url = isset($opt['url']) ? (string) $opt['url'] : trim((string) ($qyt['CONSUME_NOTIFY_URL'] ?? ''));
if ($url === '') {
$url = 'http://127.0.0.1/qytconsume.php';
}
// ---------------- 取订单(可选) ----------------
$pdo = null;
$order = null;
try {
$pdo = new PDO(
'mysql:host=' . ($db['HOSTNAME'] ?? '127.0.0.1') . ';port=' . ($db['HOSTPORT'] ?? '3306')
. ';dbname=' . ($db['DATABASE'] ?? 'oil') . ';charset=' . ($db['CHARSET'] ?? 'utf8'),
$db['USERNAME'] ?? 'root', $db['PASSWORD'] ?? '',
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);
} catch (Throwable $e) {
echo "提示:连不上数据库({$e->getMessage()}),将只发送推送、不做前后对比\n\n";
}
if ($pdo) {
$sql = $orderId > 0
? 'SELECT * FROM yoshop_partners_order WHERE order_id = ? LIMIT 1'
: 'SELECT * FROM yoshop_partners_order WHERE waybill_no_code = ? LIMIT 1';
$st = $pdo->prepare($sql);
$st->execute([$orderId > 0 ? $orderId : $code]);
$order = $st->fetch() ?: null;
if (!$order && $orderId > 0) {
exit("未找到订单 order_id={$orderId}\n");
}
}
if ($order) {
$code = (string) $order['waybill_no_code'];
if ($code === '') {
exit("订单 {$order['order_id']} 还没有运单流水号(waybill_no_code 为空),说明 7.7 还没成功下发,不能模拟加油\n");
}
}
if ($code === '') {
exit("缺少 waybill_no_code:请用 --code 指定,或用 --order 指定订单\n");
}
// ---------------- 金额 ----------------
$remain = $order ? round((float) $order['total_price'] - (float) $order['used_amount'], 2) : 0.0;
$amount = isset($opt['amount']) ? round((float) $opt['amount'], 2) : $remain;
if ($amount <= 0) {
exit("加油金额必须大于 0(订单剩余未加油金额为 " . number_format($remain, 2) . " 元,可用 --amount 指定)\n");
}
if ($order && $amount > $remain + 0.005) {
echo "⚠️ 本次金额 {$amount} 元 超过订单剩余未加油金额 " . number_format($remain, 2) . " 元,"
. "服务端会照常入账并写超额告警日志\n";
}
// ---------------- 组装报文(字段与 7.10 文档一致) ----------------
$fen = (int) round($amount * 100);
$item = [
'waybill_no' => $order['waybill_no'] ?? ('SIMW' . $code),
'order_code' => $orderCode !== '' ? $orderCode : ('SIM' . date('YmdHis') . mt_rand(1000, 9999)),
'waybill_no_code' => $code,
'quota_id' => $order['qyt_order_code'] ?? ('SIMQ' . mt_rand(100000, 999999)),
'passageway' => ($order['passageway'] ?? 'alipay') === 'pingan' ? 2 : 1,
'station_code' => '',
'station_name' => $station,
'pay_fee' => $fen,
'pay_time' => date('Y-m-d H:i:s'),
'consume_amount' => $fen,
'litter' => isset($opt['litter']) ? (string) $opt['litter'] : '',
'oil_name' => isset($opt['oil_name']) ? (string) $opt['oil_name'] : '',
'oil_price' => '',
'actual_oil_price' => '',
'scene' => 'oil',
];
$params = json_encode(['order_list' => [$item]], JSON_UNESCAPED_UNICODE);
echo "回调地址:{$url}\n";
if ($order) {
printf("订单:order_id=%s 油卡号=%s 金额=%s 已加油=%s 剩余=%s 加油次数=%s\n",
$order['order_id'], $order['oilCardNo'], $order['total_price'], $order['used_amount'],
number_format($remain, 2), $order['used_num']);
}
echo "本次加油:{$amount} 元({$fen} 分) 消费单号(去重键):{$item['order_code']}\n";
echo "params:{$params}\n\n";
if ($dryRun) {
echo "--dry-run:未发送\n";
exit;
}
// ---------------- 发送:multipart/form-data,params 放表单字段 ----------------
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
// 传数组 => cURL 自动用 multipart/form-data 编码,与企油通口径一致
CURLOPT_POSTFIELDS => ['params' => $params],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
]);
$resp = curl_exec($ch);
$http = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err = curl_error($ch);
curl_close($ch);
echo "HTTP {$http}\n响应:" . ($resp === false ? "cURL 失败:{$err}" : $resp) . "\n";
$ok = is_string($resp) && strpos($resp, '"100"') !== false;
echo $ok ? "接收端已受理(code=100)\n" : "⚠️ 接收端未返回 code=100,请查 runtime/storelog 下当天的 qyt_*.txt\n";
// ---------------- 等队列处理并对比结果 ----------------
if (!$ok || !$pdo || !$order) {
echo "\n提示:真正的落库与订单累计由 callback:queue 进程完成,请确认该进程在运行。\n";
exit;
}
echo "\n等待 callback:queue 处理";
$after = null;
for ($i = 0; $i < 10; $i++) {
sleep(1);
echo '.';
$st = $pdo->prepare('SELECT used_amount, used_num, use_status, refund_status FROM yoshop_partners_order WHERE order_id = ?');
$st->execute([$order['order_id']]);
$after = $st->fetch();
if ($after && (float) $after['used_amount'] > (float) $order['used_amount']) {
break;
}
}
echo "\n";
if ($after && (float) $after['used_amount'] > (float) $order['used_amount']) {
printf("✅ 已入账:已加油 %s -> %s,加油次数 %s -> %s,加油状态=%s\n",
$order['used_amount'], $after['used_amount'], $order['used_num'], $after['used_num'],
(int) $after['use_status'] === 1 ? '已加油' : '未加油');
$st = $pdo->prepare('SELECT id, order_code, consume_amount, notify_status FROM yoshop_qyt_consume WHERE order_id = ? ORDER BY id DESC LIMIT 3');
$st->execute([$order['order_id']]);
echo "最近消费流水:\n";
foreach ($st->fetchAll() as $r) {
printf(" #%s %s %s元 通知状态=%s\n", $r['id'], $r['order_code'],
number_format($r['consume_amount'] / 100, 2), $r['notify_status'] ? '已通知' : '待通知');
}
} else {
echo "⚠️ 10 秒内订单没有变化,可能原因:\n"
. " 1) callback:queue 进程没在跑(supervisorctl status 看一下)\n"
. " 2) 该消费单号已存在,被唯一键判为重复推送(换一个 --order-code 再试)\n"
. " 3) 处理异常,查 runtime/storelog 下当天的 " . date('YmdH') . ".txt\n";
}