177 lines
7.7 KiB
PHP
177 lines
7.7 KiB
PHP
<?php
|
||
// +----------------------------------------------------------------------
|
||
// | 补推企油通 7.10 加油明细(3 条真实推送原文,无需任何参数)
|
||
// +----------------------------------------------------------------------
|
||
// | 用法(在站点根目录执行):
|
||
// | php deploy/qyt_consume_replay.php
|
||
// |
|
||
// | 这 3 条是企油通实际推过、但因解析 bug 被我方静默忽略的报文。
|
||
// | 报文内容原样保留(order_code / pay_time / quota_id 都是真实值),
|
||
// | 因此重复执行会被 uk_consume 唯一键拦掉,不会重复累计金额。
|
||
// |
|
||
// | 推送口径与企油通一致:multipart/form-data,业务参数放表单字段 params。
|
||
// |
|
||
// | ⚠️ 会写入真实加油流水、累计订单已加油金额、并触发给下单平台的加油通知。
|
||
// | 执行前请确认:① QytNotify.php 的解析修复已部署 ② callback:queue 进程在跑。
|
||
// | 联调结束请删除本文件。
|
||
// +----------------------------------------------------------------------
|
||
declare (strict_types=1);
|
||
|
||
if (PHP_SAPI !== 'cli') {
|
||
http_response_code(403);
|
||
exit('仅限命令行执行');
|
||
}
|
||
|
||
$root = dirname(__DIR__);
|
||
|
||
// ---------------- 3 条推送原文(原样,未做任何改动) ----------------
|
||
$payloads = [];
|
||
|
||
$payloads[] = <<<'JSON'
|
||
{"order_list":[{"waybill_no":"HMWTEST20260914233556192","order_code":"2026091823001406181403169153","waybill_no_code":"HMCTEST20260914233556192","quota_id":"2026091000152611910010552563","passageway":1,"station_code":"","station_name":"中国石油北郊加油站","pay_fee":10000,"pay_time":"2026-09-18 14:25:02","consume_amount":10000,"litter":"","oil_name":"","oil_price":"","actual_oil_price":"","scene":"oil"}]}
|
||
JSON;
|
||
|
||
$payloads[] = <<<'JSON'
|
||
{"order_list":[{"waybill_no":"HMWTEST20260917171322418","order_code":"2026091823001490451444496549","waybill_no_code":"HMCTEST20260917171322418","quota_id":"2026091700152611350010049057","passageway":1,"station_code":"","station_name":"中国石化湾边加油站","pay_fee":10000,"pay_time":"2026-09-18 15:32:32","consume_amount":10000,"litter":"","oil_name":"","oil_price":"","actual_oil_price":"","scene":"oil"}]}
|
||
JSON;
|
||
|
||
$payloads[] = <<<'JSON'
|
||
{"order_list":[{"waybill_no":"HMWTEST20260917171328296","order_code":"2026091823001490451451416403","waybill_no_code":"HMCTEST20260917171328296","quota_id":"2026091700152611350010049057","passageway":1,"station_code":"","station_name":"中国石化湾边加油站","pay_fee":10000,"pay_time":"2026-09-18 15:32:53","consume_amount":10000,"litter":"","oil_name":"","oil_price":"","actual_oil_price":"","scene":"oil"}]}
|
||
JSON;
|
||
|
||
// ---------------- 回调地址 & 数据库(都取 .env) ----------------
|
||
$ini = @parse_ini_file($root . '/.env', true, INI_SCANNER_RAW) ?: [];
|
||
$url = trim((string) ($ini['QYT']['CONSUME_NOTIFY_URL'] ?? ''));
|
||
if ($url === '') {
|
||
$url = 'http://127.0.0.1/qytconsume.php';
|
||
}
|
||
|
||
$pdo = null;
|
||
try {
|
||
$db = $ini['DATABASE'] ?? [];
|
||
$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";
|
||
}
|
||
|
||
/** 按 waybill_no_code 取订单快照 */
|
||
function snap(?PDO $pdo, string $code): ?array
|
||
{
|
||
if (!$pdo) {
|
||
return null;
|
||
}
|
||
$st = $pdo->prepare('SELECT order_id, oilCardNo, total_price, used_amount, used_num, use_status
|
||
FROM yoshop_partners_order WHERE waybill_no_code = ? LIMIT 1');
|
||
$st->execute([$code]);
|
||
return $st->fetch() ?: null;
|
||
}
|
||
|
||
echo "回调地址:{$url}\n";
|
||
echo "待补推:" . count($payloads) . " 条\n";
|
||
echo str_repeat('=', 66) . "\n\n";
|
||
|
||
$okCount = $failCount = 0;
|
||
|
||
foreach ($payloads as $i => $params) {
|
||
$no = $i + 1;
|
||
$item = json_decode($params, true)['order_list'][0];
|
||
$code = $item['waybill_no_code'];
|
||
$yuan = number_format($item['consume_amount'] / 100, 2);
|
||
|
||
echo "【{$no}/" . count($payloads) . "】运单流水 {$code}\n";
|
||
echo " 加油站:{$item['station_name']} 金额:{$yuan} 元 消费单号:{$item['order_code']}\n";
|
||
|
||
$before = snap($pdo, $code);
|
||
if ($pdo && !$before) {
|
||
echo " ⚠️ 本地找不到该运单流水对应的订单,推过去也会被判为「未匹配订单」,跳过\n\n";
|
||
$failCount++;
|
||
continue;
|
||
}
|
||
if ($before) {
|
||
printf(" 订单:order_id=%s 油卡号=%s 金额=%s 已加油=%s(%s 次)\n",
|
||
$before['order_id'], $before['oilCardNo'], $before['total_price'],
|
||
$before['used_amount'], $before['used_num']);
|
||
}
|
||
|
||
// 与企油通一致:multipart/form-data,params 放表单字段(cURL 传数组即为 multipart)
|
||
$ch = curl_init();
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_URL => $url,
|
||
CURLOPT_POST => true,
|
||
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);
|
||
|
||
if ($resp === false) {
|
||
echo " ❌ cURL 失败:{$err}\n\n";
|
||
$failCount++;
|
||
continue;
|
||
}
|
||
echo " HTTP {$http} 响应:{$resp}\n";
|
||
if (strpos($resp, '"100"') === false) {
|
||
echo " ⚠️ 未返回 code=100,查 runtime/storelog 下当天的 qyt_*.txt\n\n";
|
||
$failCount++;
|
||
continue;
|
||
}
|
||
|
||
// 等 callback:queue 落库
|
||
if (!$before) {
|
||
echo " 已受理(无数据库连接,未做入账校验)\n\n";
|
||
$okCount++;
|
||
continue;
|
||
}
|
||
echo ' 等待 callback:queue 处理';
|
||
$after = null;
|
||
for ($t = 0; $t < 10; $t++) {
|
||
sleep(1);
|
||
echo '.';
|
||
$after = snap($pdo, $code);
|
||
if ($after && (float) $after['used_amount'] > (float) $before['used_amount']) {
|
||
break;
|
||
}
|
||
}
|
||
echo "\n";
|
||
|
||
if ($after && (float) $after['used_amount'] > (float) $before['used_amount']) {
|
||
printf(" ✅ 已入账:已加油 %s -> %s,次数 %s -> %s,剩余未加油 %s 元\n\n",
|
||
$before['used_amount'], $after['used_amount'], $before['used_num'], $after['used_num'],
|
||
number_format(max(0, (float) $after['total_price'] - (float) $after['used_amount']), 2));
|
||
$okCount++;
|
||
} else {
|
||
echo " ⚠️ 10 秒内订单没变化。可能原因:\n"
|
||
. " 1) callback:queue 进程没在跑(supervisorctl status)\n"
|
||
. " 2) 这条之前已经入账过,被唯一键判为重复推送(正常,不会重复累计)\n"
|
||
. " 3) 处理异常,查 runtime/storelog 下当天的 " . date('YmdH') . ".txt\n\n";
|
||
$failCount++;
|
||
}
|
||
}
|
||
|
||
echo str_repeat('=', 66) . "\n";
|
||
echo "完成:成功入账 {$okCount} 条,需关注 {$failCount} 条\n";
|
||
if ($pdo) {
|
||
echo "\n各订单当前状态:\n";
|
||
foreach ($payloads as $params) {
|
||
$code = json_decode($params, true)['order_list'][0]['waybill_no_code'];
|
||
$row = snap($pdo, $code);
|
||
if ($row) {
|
||
printf(" %s order_id=%s 金额=%s 已加油=%s(%s 次)加油状态=%s\n",
|
||
$code, $row['order_id'], $row['total_price'], $row['used_amount'], $row['used_num'],
|
||
(int) $row['use_status'] === 1 ? '已加油' : '未加油');
|
||
} else {
|
||
printf(" %s 本地无对应订单\n", $code);
|
||
}
|
||
}
|
||
}
|