1、合作商余额查询
2、分油账户司机可用额度
This commit is contained in:
@@ -2,8 +2,15 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | 企油通「运单发放结果」轮询 (7.8 waybillBatch)
|
||||
// +----------------------------------------------------------------------
|
||||
// | 为什么需要它:7.7 运单油费下发是【异步】接口,返回成功只代表受理,
|
||||
// | 真实发放结果必须按 batch_no 调 7.8 查(《企油通接口对接文档.md》§5 第 7 条)。
|
||||
// | 为什么需要它:7.7 运单油费下发是【异步】接口,返回成功只代表受理。
|
||||
// |
|
||||
// | 拿最终结果有两条路,判定逻辑共用 app\common\service\QytWaybill:
|
||||
// | · 推:3.10 发放结果通知 -> public/qytwaybill.php -> callback:queue(主路径)
|
||||
// | · 拉:本命令按 batch_no 调 7.8 查询(安全网)
|
||||
// |
|
||||
// | 接上推送后本命令不会下线:上游未配置接收地址不推送、推送重试 5 次后放弃、
|
||||
// | 我方接收端宕机或发版重启,这三种情况都只能靠轮询兜底。此时退避间隔会自动放长,
|
||||
// | 见 intervalSql()。
|
||||
// |
|
||||
// | 状态流转(oil_status_zsy):
|
||||
// | 0 未提交 --PartnersQueue 调7.7受理--> 1 发放中 --本命令查7.8--> 2 成功 / 3 失败
|
||||
@@ -27,9 +34,9 @@ namespace app\console\command;
|
||||
|
||||
use app\common\lock\RedisLock;
|
||||
use app\common\model\qyt\Enterprise as EnterpriseModel;
|
||||
use app\common\service\PartnersBalance;
|
||||
use app\common\service\QueueService;
|
||||
use app\common\service\QytConfig;
|
||||
use app\common\service\QytOil;
|
||||
use app\common\service\QytWaybill;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
@@ -40,15 +47,12 @@ class QytStatusQueue extends Command
|
||||
/** 每轮扫描的最大订单数 */
|
||||
const BATCH_LIMIT = 100;
|
||||
|
||||
/** 空转时的休眠秒数 */
|
||||
const IDLE_SLEEP = 5;
|
||||
/** 空转时的休眠秒数(只是一条轻量 SQL,不打上游,可以压到 1 秒) */
|
||||
const IDLE_SLEEP = 1;
|
||||
|
||||
/** 查询次数达到该值后仍未定论,视为异常滞留,写告警日志 */
|
||||
const STUCK_NUM = 100;
|
||||
|
||||
/** @var QueueService */
|
||||
protected $queueService;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('qyt:status')
|
||||
@@ -57,7 +61,7 @@ class QytStatusQueue extends Command
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$this->queueService = new QueueService();
|
||||
// 通知下游 / 同步小程序端都在 QytWaybill 里做,这里只负责查结果
|
||||
while (true) {
|
||||
$handled = 0;
|
||||
try {
|
||||
@@ -94,11 +98,38 @@ class QytStatusQueue extends Command
|
||||
|
||||
/**
|
||||
* 退避间隔(秒)的 SQL 表达式:查得越久间隔越长,避免高频打上游
|
||||
* 前 10 次 30s,10~30 次 120s,之后 600s
|
||||
*
|
||||
* 为什么前几次要这么密:7.7 受理后第一次 7.8 几乎必然返回「待处理」,
|
||||
* 如果第二次要等 30 秒,哪怕企油通第 8 秒就发完了,用户也得等到第 35 秒。
|
||||
* 绝大多数单在前 20 秒内就有结果,所以把这一段压到 3 秒一次,
|
||||
* 代价是每单多打上游几次;拖久的单自动退到长间隔,总 QPS 不会失控。
|
||||
*
|
||||
* 注意:若已接入 3.10 发放结果通知(后台「企油通对接设置」里打开开关),
|
||||
* 走的是上面那条「安全网」曲线,不是下面这条抢时间的曲线。
|
||||
*
|
||||
* 次数 <6 -> 3s (覆盖 0~18s,正常单在这里出结果)
|
||||
* 次数 <16 -> 10s (覆盖至约 2 分钟)
|
||||
* 次数 <26 -> 30s (覆盖至约 7 分钟)
|
||||
* 次数 <46 -> 120s (覆盖至约 47 分钟)
|
||||
* 之后 -> 600s
|
||||
*/
|
||||
protected function intervalSql(): string
|
||||
{
|
||||
return 'CASE WHEN qyt_query_num < 10 THEN 30 WHEN qyt_query_num < 30 THEN 120 ELSE 600 END';
|
||||
// 接上 3.10 发放结果通知后,结果以推送为主,轮询退为安全网:
|
||||
// 只覆盖「上游没配接收地址 / 推送重试 5 次仍失败 / 我方接收端当时不可用」
|
||||
// 这三种情况,没必要再抢在推送前面把上游打一遍。
|
||||
if (!empty(QytConfig::get()['waybill_notify'])) {
|
||||
return 'CASE'
|
||||
. ' WHEN qyt_query_num < 3 THEN 60'
|
||||
. ' WHEN qyt_query_num < 8 THEN 300'
|
||||
. ' ELSE 900 END';
|
||||
}
|
||||
return 'CASE'
|
||||
. ' WHEN qyt_query_num < 6 THEN 3'
|
||||
. ' WHEN qyt_query_num < 16 THEN 10'
|
||||
. ' WHEN qyt_query_num < 26 THEN 30'
|
||||
. ' WHEN qyt_query_num < 46 THEN 120'
|
||||
. ' ELSE 600 END';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,31 +174,16 @@ class QytStatusQueue extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
// 判定与状态跃迁跟 3.10 推送共用 QytWaybill,两条路结论必须一致
|
||||
$batchStatus = (int) ($res['data']['status'] ?? 0);
|
||||
$row = QytOil::pickWaybill($res['data'], (string) $order['waybill_no_code']);
|
||||
$row = QytWaybill::pick($res['data'], (string) $order['waybill_no_code']);
|
||||
$judged = QytWaybill::judge($batchStatus, $row);
|
||||
|
||||
// 整批处理失败,且明细里没有本条 -> 判失败
|
||||
if (!$row && $batchStatus === 5) {
|
||||
$this->markFailed($order, '企油通返回整批处理失败', $qyt);
|
||||
return;
|
||||
}
|
||||
// 明细里还没有本条:批次还在排队,继续等
|
||||
if (!$row) {
|
||||
if ($judged['result'] === QytWaybill::R_PENDING) {
|
||||
$this->alertIfStuck($order, $qyt);
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($row['handle_status']) {
|
||||
case 2: // 成功
|
||||
$this->markSuccess($order, $row['remark'] ?: '发放成功', $qyt);
|
||||
break;
|
||||
case 3: // 失败
|
||||
$this->markFailed($order, $row['error_msg'] ?: '企油通发放失败', $qyt);
|
||||
break;
|
||||
default: // 1 待处理,或未知值 -> 继续等
|
||||
$this->alertIfStuck($order, $qyt);
|
||||
break;
|
||||
}
|
||||
QytWaybill::apply($order, $judged, '7.8 轮询');
|
||||
} catch (\Throwable $e) {
|
||||
$this->log("order={$orderId} 轮询异常:" . $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine());
|
||||
} finally {
|
||||
@@ -175,60 +191,6 @@ class QytStatusQueue extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发放成功:条件跃迁 1 -> 2,胜出者才回调下单平台
|
||||
*/
|
||||
protected function markSuccess(array $order, string $text, QytOil $qyt): void
|
||||
{
|
||||
$affected = Db::name('partners_order')
|
||||
->where('order_id', $order['order_id'])
|
||||
->where('oil_status_zsy', 1)
|
||||
->update([
|
||||
'oil_status' => 1,
|
||||
'oil_status_zsy' => 2,
|
||||
'oil_time' => time(),
|
||||
'oil_text' => $text,
|
||||
'update_time' => time(),
|
||||
]);
|
||||
if (!$affected) {
|
||||
return;
|
||||
}
|
||||
$this->queueService->push('notify_queue', json_encode([
|
||||
'order_id' => $order['order_id'],
|
||||
'type' => 'add',
|
||||
'optType' => 'share_oil',
|
||||
'retry_count' => 0,
|
||||
], 320));
|
||||
$qyt->saveLog("7.8 确认发放成功 order={$order['order_id']} batch_no={$order['batch_no']}"
|
||||
. " 查询次数={$order['qyt_query_num']}");
|
||||
}
|
||||
|
||||
/**
|
||||
* 发放失败:条件跃迁 1 -> 3,胜出者才退款(保证只退一次)
|
||||
*/
|
||||
protected function markFailed(array $order, string $reason, QytOil $qyt): void
|
||||
{
|
||||
$affected = Db::name('partners_order')
|
||||
->where('order_id', $order['order_id'])
|
||||
->where('oil_status_zsy', 1)
|
||||
->update([
|
||||
'oil_status_zsy' => 3,
|
||||
'oil_text' => '发放失败:' . $reason,
|
||||
'update_time' => time(),
|
||||
]);
|
||||
if (!$affected) {
|
||||
return;
|
||||
}
|
||||
PartnersBalance::refund(
|
||||
(int) $order['partners_id'],
|
||||
(float) $order['total_price'],
|
||||
(string) $order['partners_order_no'],
|
||||
(int) $order['order_id'],
|
||||
(int) $order['store_id']
|
||||
);
|
||||
$qyt->saveLog("7.8 确认发放失败 order={$order['order_id']} 原因={$reason},已回补合作商余额 {$order['total_price']}");
|
||||
}
|
||||
|
||||
/**
|
||||
* 长期拿不到结果时告警。只写日志,不改状态、不退款
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user