文件
xionggeshop/addons/shopro_huifu/command/SplitRetry.php
可乐加冰 6a654070ed ```
feat(split): 新增分账订单线下结案功能

- 添加 SplitCloseService 类用于处理订单结案逻辑
- 实现订单结案状态检查和标记功能
- 在汇付分账重试逻辑中加入结案状态验证,防止已结案订单继续重试
- 更新分账手动服务,添加结案操作类型
- 扩展钱包结算类,增加结案相关诊断方法
- 修改测试脚本,支持批量标记订单为已结案状态
- 添加数据库升级脚本,增加结案相关字段和菜单权限
```
2026-10-24 21:18:48 +08:00

117 行
4.4 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?php
namespace addons\shopro_huifu\command;
use addons\shopro\library\split\Config;
use addons\shopro\library\split\SplitCloseService;
use addons\shopro\model\split\SplitOrder;
use addons\shopro_huifu\library\HuifuSplitService;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\Db;
class SplitRetry extends Command
{
protected function configure()
{
$this->setName('shopro_huifu:split-retry')
->addOption('sn', null, Option::VALUE_OPTIONAL, '指定订单号重试,多个用逗号分隔')
->addOption('force', null, Option::VALUE_NONE, '忽略 next_retry_time,立即重试')
->setDescription('Retry failed Huifu split confirm orders');
}
protected function execute(Input $input, Output $output)
{
$config = new Config();
if (!$config->isEnable()) {
$output->writeln('Split disabled.');
return 1;
}
$force = (bool) $input->getOption('force');
$snOpt = trim((string) $input->getOption('sn'));
$service = new HuifuSplitService();
$rows = [];
if ($snOpt !== '') {
foreach (preg_split('/[\s,,]+/', $snOpt) as $sn) {
$sn = trim($sn);
if ($sn === '') {
continue;
}
$order = Db::name('shopro_order')->where('order_sn', $sn)->find();
if (!$order && strlen($sn) < 24) {
$order = Db::name('shopro_order')->where('order_sn', 'like', $sn . '%')->order('id', 'desc')->find();
}
if (!$order) {
$output->writeln("[SKIP] 订单不存在: {$sn}");
continue;
}
$split = SplitOrder::where('order_id', $order['id'])
->where('channel', 'huifu')
->order('id', 'desc')
->find();
if (!$split) {
$output->writeln("[SKIP] 无汇付分账记录: {$sn}");
continue;
}
if ((int) $split['status'] === 2) {
$output->writeln("[OK] 已分账成功: {$sn}");
continue;
}
if ((int) $split['status'] === SplitCloseService::STATUS_CLOSED
|| (new SplitCloseService())->isClosed((int) $order['id'])) {
$output->writeln("[SKIP] 已线下结案: {$sn}");
continue;
}
$rows[] = $split;
}
} else {
$query = SplitOrder::where('channel', 'huifu')
->where('status', 4)
->where('retry_count', '<', $config->getRetryMax());
if (!$force) {
$query->where('next_retry_time', '<=', time());
}
$rows = $query->limit(20)->select();
}
if (!$rows) {
$output->writeln('无可重试记录。若刚 confirm 成功,可等 5–30 分钟或加 --force;指定单号:--sn=订单号 --force');
return 0;
}
$ok = 0;
$fail = 0;
$closeService = new SplitCloseService();
foreach ($rows as $row) {
if ((int) $row['status'] === SplitCloseService::STATUS_CLOSED
|| $closeService->isClosed((int) $row['order_id'])) {
$output->writeln('[SKIP] 已线下结案 order_sn=' . ($row['order_sn'] ?? ''));
continue;
}
$output->writeln('retry split#' . $row['id'] . ' order_sn=' . ($row['order_sn'] ?? ''));
$result = $service->retry($row['id']);
if ($result) {
$output->writeln(' [OK]');
$ok++;
} else {
$latest = SplitOrder::where('order_id', $row['order_id'])
->where('channel', 'huifu')
->order('id', 'desc')
->find();
$hint = $latest && !empty($latest['wx_result'])
? mb_substr((string) $latest['wx_result'], 0, 200)
: '仍失败,见后台分账详情';
$output->writeln(' [FAIL] ' . $hint);
$fail++;
}
}
$output->writeln("完成:成功 {$ok},失败 {$fail}");
return $fail > 0 ? 1 : 0;
}
}