/
itp_practice
/
itp_backend
Обзор
Документация
Войти
/
itp_practice
/
itp_backend
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
app/Console/Commands/SyncTapStatusesCommand.php
202 строки
8 KB
vivanenko
run taps
29 май 2025, 21:05
29 май 2025, 21:05
b91be9d
Код
Авторство
О чём код?
<?php namespace App\Console\Commands; use App\Models\Tap; use App\Services\TapAppService; use Illuminate\Console\Command; use Illuminate\Support\Facades\Log; /** * Команда для синхронизации статусов тапов с Supervisor * * Следует принципам SOLID: * - Single Responsibility: Только синхронизация статусов * - Dependency Inversion: Зависит от TapAppService абстракции */ class SyncTapStatusesCommand extends Command { /** * The name and signature of the console command. */ protected $signature = 'taps:sync-statuses {--user-id= : Синхронизировать тапы конкретного пользователя} {--tap-id= : Синхронизировать конкретный тап} {--active-only : Синхронизировать только активные тапы} {--force : Принудительная синхронизация всех тапов}'; /** * The console command description. */ protected $description = 'Синхронизирует статусы тапов с Supervisor на регулярной основе'; public function __construct( private readonly TapAppService $tapAppService ) { parent::__construct(); } /** * Execute the console command. */ public function handle(): int { $startTime = microtime(true); Log::info('Starting tap statuses synchronization', [ 'command' => $this->signature, 'options' => $this->options(), ]); $this->info('🔄 Начинаем синхронизацию статусов тапов...'); try { // Business Logic Layer - определение области синхронизации $taps = $this->getTapsToSync(); if ($taps->isEmpty()) { $this->warn('⚠️ Нет тапов для синхронизации'); return self::SUCCESS; } $this->info("📊 Найдено тапов для синхронизации: {$taps->count()}"); // Progress bar для user experience $progressBar = $this->output->createProgressBar($taps->count()); $progressBar->setFormat('verbose'); $results = [ 'total' => $taps->count(), 'synced' => 0, 'changed' => 0, 'errors' => 0, 'error_details' => [], ]; // Business Logic Layer - синхронизация каждого тапа foreach ($taps as $tap) { $progressBar->advance(); try { $syncResult = $this->tapAppService->syncTapStatus($tap->id); if ($syncResult['synced']) { $results['synced']++; if ($syncResult['status_changed'] ?? false) { $results['changed']++; $this->line("\n✅ Tap {$tap->id}: статус обновлен на {$syncResult['database_status']}"); } } else { $results['errors']++; $results['error_details'][] = "Tap {$tap->id}: " . ($syncResult['error'] ?? 'Unknown error'); } } catch (\Exception $e) { $results['errors']++; $results['error_details'][] = "Tap {$tap->id}: {$e->getMessage()}"; Log::error('Failed to sync tap status in command', [ 'tap_id' => $tap->id, 'error' => $e->getMessage(), ]); } } $progressBar->finish(); $this->newLine(2); // Вывод результатов $this->displayResults($results, microtime(true) - $startTime); Log::info('Tap statuses synchronization completed', [ 'results' => $results, 'execution_time' => microtime(true) - $startTime, ]); return self::SUCCESS; } catch (\Exception $e) { $this->error('❌ Критическая ошибка при синхронизации: ' . $e->getMessage()); Log::error('Critical error in tap sync command', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); return self::FAILURE; } } /** * Data Access Layer - получение тапов для синхронизации */ private function getTapsToSync(): \Illuminate\Database\Eloquent\Collection { $query = Tap::with('tapApp'); // Фильтрация по конкретному тапу if ($tapId = $this->option('tap-id')) { return $query->where('id', $tapId)->get(); } // Фильтрация по пользователю if ($userId = $this->option('user-id')) { $query->where('crm_user_id', $userId); } // Фильтрация только активных if ($this->option('active-only')) { $query->whereIn('status', [\App\Enums\TapStatus::ACTIVE, \App\Enums\TapStatus::NEW]); } // Если не принудительная синхронизация, берем тапы, которые давно не проверялись if (!$this->option('force')) { $query->where(function ($q) { $q->whereNull('last_process_check') ->orWhere('last_process_check', '<', now()->subMinutes(5)); }); } return $query->get(); } /** * UI Layer - отображение результатов синхронизации */ private function displayResults(array $results, float $executionTime): void { $this->info('📋 Результаты синхронизации:'); $this->table( ['Метрика', 'Значение'], [ ['Всего тапов', $results['total']], ['Успешно синхронизировано', $results['synced']], ['Статусы изменены', $results['changed']], ['Ошибок', $results['errors']], ['Время выполнения', round($executionTime, 2) . ' сек'], ] ); // Отображение ошибок если есть if (!empty($results['error_details'])) { $this->error('❌ Детали ошибок:'); foreach ($results['error_details'] as $error) { $this->line(" • {$error}"); } } // Success rate $successRate = $results['total'] > 0 ? round(($results['synced'] / $results['total']) * 100, 1) : 0; if ($successRate >= 95) { $this->info("🎉 Синхронизация завершена успешно! (Success rate: {$successRate}%)"); } elseif ($successRate >= 80) { $this->warn("⚠️ Синхронизация завершена с предупреждениями (Success rate: {$successRate}%)"); } else { $this->error("❌ Синхронизация завершена с ошибками (Success rate: {$successRate}%)"); } } }