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); /** @var AgentLevelServices $agentLevelServices */ $agentLevelServices = app()->make(AgentLevelServices::class); /** @var UserServices $userServices */ $userServices = app()->make(UserServices::class); $patched = 0; $skipped = 0; foreach ($orders as $order) { // 幂等检查:points_release_log 中是否已有 reward_direct/reward_umbrella 记录 $hasRewardLog = Db::name('points_release_log') ->where('order_id', $order['order_id']) ->whereIn('type', ['reward_direct', 'reward_umbrella']) ->count(); if ($hasRewardLog > 0) { $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 { $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']); $patched++; $output->writeln(sprintf( ' [PATCHED] 订单 #%d (%s) uid=%d 等级检查+积分奖励已补发', $order['id'], $order['order_id'], $uid )); } 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; } }