2026-03-24 20:40:46 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
|
|
namespace app\command;
|
|
|
|
|
|
|
2026-03-25 07:38:12 +08:00
|
|
|
|
use app\services\agent\AgentLevelServices;
|
2026-03-24 20:40:46 +08:00
|
|
|
|
use app\services\hjf\PointsRewardServices;
|
2026-03-25 07:38:12 +08:00
|
|
|
|
use app\services\user\UserServices;
|
2026-03-24 20:40:46 +08:00
|
|
|
|
use think\console\Command;
|
|
|
|
|
|
use think\console\Input;
|
|
|
|
|
|
use think\console\input\Option;
|
|
|
|
|
|
use think\console\Output;
|
|
|
|
|
|
use think\facade\Db;
|
|
|
|
|
|
use think\facade\Log;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 补偿历史报单订单缺失的积分奖励
|
|
|
|
|
|
*
|
|
|
|
|
|
* 用法:
|
|
|
|
|
|
* php think hjf:patch-rewards # 扫描全部报单订单
|
|
|
|
|
|
* php think hjf:patch-rewards --order-id=11 # 仅补偿指定订单
|
|
|
|
|
|
* php think hjf:patch-rewards --dry-run # 仅扫描不执行
|
|
|
|
|
|
*/
|
|
|
|
|
|
class HjfPatchMissingRewards extends Command
|
|
|
|
|
|
{
|
|
|
|
|
|
protected function configure(): void
|
|
|
|
|
|
{
|
|
|
|
|
|
$this->setName('hjf:patch-rewards')
|
|
|
|
|
|
->setDescription('补偿历史报单订单缺失的冻结积分奖励')
|
|
|
|
|
|
->addOption('order-id', null, Option::VALUE_OPTIONAL, '指定订单ID,不传则扫描全部')
|
|
|
|
|
|
->addOption('dry-run', null, Option::VALUE_NONE, '仅扫描打印,不实际执行');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected function execute(Input $input, Output $output): int
|
|
|
|
|
|
{
|
|
|
|
|
|
$orderId = $input->getOption('order-id');
|
|
|
|
|
|
$dryRun = $input->getOption('dry-run');
|
|
|
|
|
|
|
|
|
|
|
|
$output->writeln('[HjfPatchRewards] 开始扫描缺失积分奖励的报单订单...');
|
|
|
|
|
|
|
|
|
|
|
|
$query = Db::name('store_order')
|
|
|
|
|
|
->where('is_queue_goods', 1)
|
|
|
|
|
|
->where('paid', 1)
|
|
|
|
|
|
->where('is_del', 0)
|
|
|
|
|
|
->where('is_system_del', 0);
|
|
|
|
|
|
|
|
|
|
|
|
if ($orderId) {
|
|
|
|
|
|
$query->where('id', (int)$orderId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$orders = $query->field('id,order_id,uid,spread_uid,one_brokerage')->select()->toArray();
|
|
|
|
|
|
|
|
|
|
|
|
if (empty($orders)) {
|
|
|
|
|
|
$output->writeln('[HjfPatchRewards] 没有找到符合条件的报单订单');
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$output->writeln(sprintf('[HjfPatchRewards] 找到 %d 笔报单订单', count($orders)));
|
|
|
|
|
|
|
|
|
|
|
|
/** @var PointsRewardServices $pointsService */
|
|
|
|
|
|
$pointsService = app()->make(PointsRewardServices::class);
|
2026-03-25 07:38:12 +08:00
|
|
|
|
/** @var AgentLevelServices $agentLevelServices */
|
|
|
|
|
|
$agentLevelServices = app()->make(AgentLevelServices::class);
|
|
|
|
|
|
/** @var UserServices $userServices */
|
|
|
|
|
|
$userServices = app()->make(UserServices::class);
|
|
|
|
|
|
|
2026-03-24 20:40:46 +08:00
|
|
|
|
$patched = 0;
|
|
|
|
|
|
$skipped = 0;
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($orders as $order) {
|
2026-03-25 07:38:12 +08:00
|
|
|
|
// 幂等检查:points_release_log 中是否已有 reward_direct/reward_umbrella 记录
|
2026-03-24 20:40:46 +08:00
|
|
|
|
$hasRewardLog = Db::name('points_release_log')
|
|
|
|
|
|
->where('order_id', $order['order_id'])
|
2026-03-25 07:38:12 +08:00
|
|
|
|
->whereIn('type', ['reward_direct', 'reward_umbrella'])
|
2026-03-24 20:40:46 +08:00
|
|
|
|
->count();
|
|
|
|
|
|
|
2026-03-25 07:38:12 +08:00
|
|
|
|
if ($hasRewardLog > 0) {
|
2026-03-24 20:40:46 +08:00
|
|
|
|
$skipped++;
|
|
|
|
|
|
$output->writeln(sprintf(' [SKIP] 订单 #%d (%s) 已有积分奖励记录', $order['id'], $order['order_id']));
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!$order['spread_uid'] || $order['spread_uid'] <= 0) {
|
|
|
|
|
|
$skipped++;
|
|
|
|
|
|
$output->writeln(sprintf(' [SKIP] 订单 #%d (%s) 无推荐人', $order['id'], $order['order_id']));
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($dryRun) {
|
|
|
|
|
|
$output->writeln(sprintf(
|
|
|
|
|
|
' [DRY-RUN] 订单 #%d (%s) uid=%d spread_uid=%d 需要补发积分',
|
|
|
|
|
|
$order['id'], $order['order_id'], $order['uid'], $order['spread_uid']
|
|
|
|
|
|
));
|
|
|
|
|
|
$patched++;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
2026-03-25 07:38:12 +08:00
|
|
|
|
$uid = (int)$order['uid'];
|
|
|
|
|
|
// 先执行等级升级检查,确保积分奖励使用正确的 agent_level
|
|
|
|
|
|
$userCacheInfo = $userServices->getUserCacheInfo($uid);
|
|
|
|
|
|
$spreadUid = $userCacheInfo ? (int)($userCacheInfo['spread_uid'] ?? 0) : (int)$order['spread_uid'];
|
|
|
|
|
|
$twoSpreadUid = 0;
|
|
|
|
|
|
if ($spreadUid > 0 && $oneUserInfo = $userServices->getUserCacheInfo($spreadUid)) {
|
|
|
|
|
|
$twoSpreadUid = $userServices->getSpreadUid($spreadUid, $oneUserInfo, false);
|
|
|
|
|
|
}
|
|
|
|
|
|
$uids = array_values(array_filter(array_unique([$uid, $spreadUid, $twoSpreadUid])));
|
|
|
|
|
|
$agentLevelServices->checkUserLevelFinish($uid, $uids);
|
|
|
|
|
|
|
|
|
|
|
|
// 发放积分奖励(PointsRewardServices 内部已做幂等检查)
|
|
|
|
|
|
$pointsService->reward($uid, (string)$order['order_id'], (int)$order['id']);
|
2026-03-24 20:40:46 +08:00
|
|
|
|
$patched++;
|
|
|
|
|
|
$output->writeln(sprintf(
|
2026-03-25 07:38:12 +08:00
|
|
|
|
' [PATCHED] 订单 #%d (%s) uid=%d 等级检查+积分奖励已补发',
|
|
|
|
|
|
$order['id'], $order['order_id'], $uid
|
2026-03-24 20:40:46 +08:00
|
|
|
|
));
|
|
|
|
|
|
} catch (\Throwable $e) {
|
|
|
|
|
|
$output->writeln(sprintf(
|
|
|
|
|
|
' [ERROR] 订单 #%d (%s): %s',
|
|
|
|
|
|
$order['id'], $order['order_id'], $e->getMessage()
|
|
|
|
|
|
));
|
|
|
|
|
|
Log::error("[HjfPatchRewards] 订单 #{$order['id']} 补发失败: " . $e->getMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$output->writeln(sprintf(
|
|
|
|
|
|
'[HjfPatchRewards] 完成:补发 %d 笔,跳过 %d 笔%s',
|
|
|
|
|
|
$patched, $skipped, $dryRun ? ' (dry-run 模式)' : ''
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|