> */ public array $archiveFolders = []; /** @var array> */ public array $moduleRows = []; /** @var array|null */ public ?array $googleWorkspaceStatus = null; public static function canAccess(): bool { $user = auth()->user(); return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'fornitore']); } public function mount(): void { [$fornitore] = $this->resolveOperatoreContext(allowAdminWithoutSupplier: true); if (! $fornitore instanceof Fornitore) { $this->missingAdminContext = true; return; } $this->fornitore = $fornitore; $this->refreshArchiveSummary(); } public function saveUploadedTecnoRepairMdb(): void { if (! $this->fornitore instanceof Fornitore) { return; } $upload = $this->tecnorepairMdbUpload; if (! $upload instanceof TemporaryUploadedFile) { Notification::make()->title('Seleziona prima un file MDB')->warning()->send(); return; } $extension = strtolower((string) $upload->getClientOriginalExtension()); if ($extension !== 'mdb') { Notification::make()->title('Carica un file .mdb')->warning()->send(); return; } $relativeBase = $this->getArchiveRelativeBase(); if ($relativeBase === null) { Notification::make()->title('Archivio fornitore non disponibile')->danger()->send(); return; } $filename = 'TecnoRepairDB-' . now()->format('Ymd-His') . '.mdb'; $stored = $upload->storeAs($relativeBase . '/tecnorepair/imports', $filename, 'local'); $this->tecnorepairMdbPath = storage_path('app/' . $stored); $this->tecnorepairMdbUpload = null; $this->refreshArchiveSummary(); Notification::make()->title('Archivio TecnoRepair caricato')->body($filename)->success()->send(); } public function importTecnoRepairFromArchive(bool $dryRun = false): void { if (! $this->fornitore instanceof Fornitore) { return; } $mdbPath = trim($this->tecnorepairMdbPath); if ($mdbPath === '' || ! is_file($mdbPath)) { Notification::make()->title('Percorso MDB non valido')->warning()->send(); return; } $adminId = (int) ($this->fornitore->amministratore_id ?? 0); if ($adminId <= 0) { Notification::make()->title('Amministratore del fornitore non trovato')->danger()->send(); return; } try { Artisan::call('tecnorepair:import-legacy', [ 'amministratore' => $adminId, '--mdb' => $mdbPath, '--fornitore-id' => (int) $this->fornitore->id, '--force-primary' => true, '--dry-run' => $dryRun, ]); } catch (\Throwable $e) { Notification::make()->title('Import TecnoRepair fallito')->body($e->getMessage())->danger()->send(); return; } $this->lastImportOutput = trim(Artisan::output()); $this->refreshArchiveSummary(); Notification::make() ->title($dryRun ? 'Simulazione TecnoRepair completata' : 'Import TecnoRepair completato') ->body($this->lastImportOutput !== '' ? $this->lastImportOutput : 'Operazione completata.') ->success() ->send(); } public function getSchedaFornitoreUrl(): string { return FornitoreScheda::getUrl(['record' => (int) ($this->fornitore?->id ?? 0)], panel: 'admin-filament'); } public function getTicketsUrl(): string { return TicketOperativi::getUrl(['fornitore' => (int) ($this->fornitore?->id ?? 0)], panel: 'admin-filament'); } public function getProdottiUrl(): string { return ProdottiCatalogo::getUrl(['fornitore' => (int) ($this->fornitore?->id ?? 0)], panel: 'admin-filament'); } public function getGoogleConnectUrl(): string { return route('oauth.google.redirect', [ 'return_to' => request()->getRequestUri(), ]); } public function getGoogleDisconnectUrl(): string { return route('oauth.google.disconnect', [ 'return_to' => request()->getRequestUri(), ]); } private function refreshArchiveSummary(): void { $relativeBase = $this->getArchiveRelativeBase(); $absoluteBase = $relativeBase ? storage_path('app/' . $relativeBase) : null; if ($relativeBase !== null) { foreach ([ 'documenti', 'rubrica', 'fe', 'prodotti', 'comunicazioni', 'tecnorepair/imports', 'tecnorepair/allegati', 'temp/upload', 'temp/processing', 'logs', ] as $folder) { Storage::disk('local')->makeDirectory($relativeBase . '/' . $folder); } } $this->archiveFolders = $relativeBase === null ? [] : [ ['label' => 'Base archivio', 'path' => (string) $absoluteBase], ['label' => 'Rubrica fornitore', 'path' => storage_path('app/' . $relativeBase . '/rubrica')], ['label' => 'FE fornitore', 'path' => storage_path('app/' . $relativeBase . '/fe')], ['label' => 'Prodotti e catalogo', 'path' => storage_path('app/' . $relativeBase . '/prodotti')], ['label' => 'Comunicazioni / Post-it', 'path' => storage_path('app/' . $relativeBase . '/comunicazioni')], ['label' => 'TecnoRepair import', 'path' => storage_path('app/' . $relativeBase . '/tecnorepair/imports')], ]; if ($relativeBase !== null && $this->tecnorepairMdbPath === '') { $latest = collect(Storage::disk('local')->files($relativeBase . '/tecnorepair/imports')) ->filter(fn(string $path): bool => str_ends_with(strtolower($path), '.mdb')) ->sortDesc() ->first(); if (is_string($latest) && $latest !== '') { $this->tecnorepairMdbPath = storage_path('app/' . $latest); } } $stats = $this->fornitore?->tecnorepair_stats ?? ['total' => 0, 'open' => 0, 'closed' => 0, 'serials' => 0]; $this->googleWorkspaceStatus = $this->resolveGoogleWorkspaceStatus(); $this->moduleRows = [ ['module' => 'Rubrica fornitore', 'status' => 'pronto', 'note' => 'Vista fornitore filtrata ma agganciata all\'anagrafica unica.'], ['module' => 'Google Workspace', 'status' => data_get($this->googleWorkspaceStatus, 'connected', false) ? 'collegato' : 'da collegare', 'note' => 'Rubrica e sincronizzazioni smartphone riusano l\'account Google del contesto amministratore.'], ['module' => 'TecnoRepair MDB', 'status' => ((int) ($stats['total'] ?? 0) > 0) ? 'importato' : 'da importare', 'note' => 'Schede: ' . (int) ($stats['total'] ?? 0) . ' · aperte: ' . (int) ($stats['open'] ?? 0) . ' · chiuse: ' . (int) ($stats['closed'] ?? 0)], ['module' => 'Catalogo fornitore', 'status' => 'attivo', 'note' => 'Il catalogo vero resta nella pagina Prodotti.'], ['module' => 'Comunicazioni / Post-it', 'status' => 'predisposto', 'note' => 'Cartelle e contesto archivio pronti per agganciare chiamate, post-it ed email.'], ['module' => 'FE e documenti', 'status' => 'predisposto', 'note' => 'Archivio separato per FE, documenti e flussi contabili del fornitore.'], ]; } /** * @return array|null */ private function resolveGoogleWorkspaceStatus(): ?array { $amministratore = $this->fornitore?->amministratore; if (! $amministratore) { return null; } $oauth = (array) (($amministratore->impostazioni['google']['oauth'] ?? null) ?: []); return [ 'connected' => (bool) ($oauth['connected'] ?? false), 'email' => (string) ($oauth['email'] ?? ''), 'name' => (string) ($oauth['name'] ?? ''), 'connected_at' => (string) ($oauth['connected_at'] ?? ''), ]; } private function getArchiveRelativeBase(): ?string { if (! $this->fornitore instanceof Fornitore) { return null; } return ArchivioPaths::fornitoreBase($this->fornitore, $this->fornitore->amministratore); } }