feat(shopro_wechat_trade): 添加重新同步物流信息命令

新增 ResyncShipping 命令,支持强制重新上传微信物流信息,
不依赖 sync 表的 failed/pending 状态,适用于修改自提配置后
需要重传的场景。

同时修改 RetryFailed 命令,在没有待重试记录时提供操作提示,
并扩展 WxShippingService 的 retryFailed 方法支持处理
failed 状态的记录。
```
这个提交包含在:
可乐加冰
2026-10-09 13:01:01 +08:00
父节点 87ce558c07
当前提交 66641f8a05
共有 4 个文件被更改,包括 107 次插入 和 3 次删除

查看文件

@@ -0,0 +1,65 @@
<?php
namespace addons\shopro_wechat_trade\command;
use addons\shopro_wechat_trade\library\Bridge;
use addons\shopro_wechat_trade\library\WxShippingService;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
/**
* 强制再次 upload_shipping_info(不依赖 sync 表 failed/pending)
*/
class ResyncShipping extends Command
{
protected function configure()
{
$this->setName('shopro_wechat_trade:resync-shipping')
->addOption('sn', null, Option::VALUE_REQUIRED, '订单号,多个英文逗号分隔')
->addOption('id', null, Option::VALUE_REQUIRED, '订单 id,多个英文逗号分隔')
->setDescription('Force re-upload WeChat shipping (e.g. after force self-pickup config)');
}
protected function execute(Input $input, Output $output)
{
if (!Bridge::isEnabled()) {
$output->writeln('[FAIL] shopro_wechat_trade 未启用');
return 1;
}
$sns = [];
$snOpt = trim((string) $input->getOption('sn'));
if ($snOpt !== '') {
foreach (preg_split('/[\s,,]+/', $snOpt) as $sn) {
$sn = trim($sn);
if ($sn !== '') {
$sns[] = $sn;
}
}
}
$idOpt = trim((string) $input->getOption('id'));
if ($idOpt !== '') {
foreach (preg_split('/[\s,,]+/', $idOpt) as $id) {
$id = intval($id);
if ($id > 0) {
$row = \think\Db::name('shopro_order')->where('id', $id)->value('order_sn');
if ($row) {
$sns[] = $row;
}
}
}
}
if (!$sns) {
$output->writeln('请指定 --sn=订单号 或 --id=订单id');
return 1;
}
$service = new WxShippingService();
$result = $service->resyncShippingByOrderSns(array_unique($sns));
$output->writeln('Resync shipping: ok=' . $result['ok'] . ', fail=' . $result['fail']);
$output->writeln('说明:retry-failed 只处理 sync 表 pending/failed;已成功的老单请用本命令重传。');
return $result['fail'] > 0 ? 1 : 0;
}
}

查看文件

@@ -22,5 +22,9 @@ class RetryFailed extends Command
$limit = intval($input->getOption('limit') ?: 50);
$count = (new WxShippingService())->retryFailed($limit);
$output->writeln('Retried ' . $count . ' sync record(s).');
if ($count === 0) {
$output->writeln('若无 pending/failed 记录,已成功同步的单需:php think shopro_wechat_trade:resync-shipping --sn=订单号');
$output->writeln('从未同步且已发货:php think shopro_wechat_trade:backfill --limit=100');
}
}
}

查看文件

@@ -142,9 +142,13 @@ class WxShippingService
{
$now = time();
$rows = Db::name('shopro_wechat_trade_sync')
->where('status', 'pending')
->where('retry_count', '>', 0)
->where('next_retry_time', '<=', $now)
->where(function ($q) use ($now) {
$q->where(function ($q2) use ($now) {
$q2->where('status', 'pending')
->where('retry_count', '>', 0)
->where('next_retry_time', '<=', $now);
})->whereOr('status', 'failed');
})
->order('id', 'asc')
->limit($limit)
->select();
@@ -164,4 +168,34 @@ class WxShippingService
}
return $count;
}
/**
* 按订单号再次调用 upload_shipping_info(已有 success 也会重传,用于改自提等)
*/
public function resyncShippingByOrderSns(array $orderSns)
{
$ok = 0;
$fail = 0;
foreach ($orderSns as $sn) {
$sn = trim((string) $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) {
$fail++;
continue;
}
try {
$this->syncOrderShipping((int) $order['id']);
$ok++;
} catch (\Exception $e) {
$fail++;
}
}
return ['ok' => $ok, 'fail' => $fail];
}
}

查看文件

@@ -33,6 +33,7 @@ return [
'addons\shopro_wechat_trade\command\ProbeOrderPath',
'addons\shopro_wechat_trade\command\BackfillShipping',
'addons\shopro_wechat_trade\command\RetryFailed',
'addons\shopro_wechat_trade\command\ResyncShipping',
'addons\shopro_wechat_trade\command\ConfirmOrders',
'addons\shopro_wechat_trade\command\VerifyInstall',
'addons\shopro_wechat_trade\command\InstallFull',