option('token') ?: config('services.approagency.token'); if (empty($token)) { $this->error('Provide --token= or set APPROAGENCY_ADMIN_TOKEN in .env'); return 1; } $users = User::whereNull('first_name') ->whereNotNull('mobile') ->get(); $this->info("Found {$users->count()} users with missing first_name. Syncing..."); $synced = 0; $failed = 0; foreach ($users as $user) { $retries = 0; while ($retries <= 3) { try { $response = Http::withToken($token) ->retry(2, 2000) ->get('https://api.approagency.ir/api/admin/users', [ 'mobile' => $user->mobile, 'per_page' => 1, ]); if ($response->status() === 429) { $retries++; $wait = $retries * 3; $this->warn(" rate limited on {$user->mobile}, waiting {$wait}s..."); sleep($wait); continue; } if ($response->successful()) { $data = $response->json('data.0'); if ($data) { $user->update([ 'first_name' => $data['first_name'] ?? $user->first_name, 'last_name' => $data['last_name'] ?? $user->last_name, 'age' => $data['age'] ?? $user->age, 'gender' => $data['gender'] ?? $user->gender, 'birthday' => $data['birthday'] ?? $user->birthday, 'identifier' => $data['uuid'] ?? $user->identifier, ]); $name = $data['first_name'] ?? 'null'; $this->line(" synced: {$user->mobile} → {$name}"); $synced++; } } else { $this->warn(" skip: {$user->mobile} (HTTP {$response->status()})"); $failed++; } break; } catch (\Exception $e) { $retries++; if ($retries > 3) { $this->error(" failed: {$user->mobile} — {$e->getMessage()}"); $failed++; } else { sleep($retries * 2); } } } sleep(3); // 3s between requests } $this->info("Done. Synced: {$synced}, Failed: {$failed}"); return 0; } }