diff --git a/app/Filament/Pages/Condomini/CatastoHub.php b/app/Filament/Pages/Condomini/CatastoHub.php index 7e643e3..276aa6f 100644 --- a/app/Filament/Pages/Condomini/CatastoHub.php +++ b/app/Filament/Pages/Condomini/CatastoHub.php @@ -923,21 +923,77 @@ public function interrogaGeometriaStabile(): void } try { + $service = new SisterCatastoService(); + $dirPath = $service->getStoragePath($this->stabileAttivo->id); + $tipoCatasto = 'F'; + $uffProvinciale = 'ROMA Territorio-RM'; + $cittaName = $this->stabileAttivo->citta ?? 'ROMA'; + $denomComune = $service->getComuneCat($this->stabileAttivo->id, $uffProvinciale, $cittaName); + $foglio = (string)($this->stabileAttivo->foglio ?? $this->stabileAttivo->foglio_catasto ?? ''); + $particella = (string)($this->stabileAttivo->particella_catasto ?? $this->stabileAttivo->mappale ?? ''); + + if (!empty($foglio) && !empty($particella)) { + $result = $service->ricercaGeometriaImmobile( + $this->stabileAttivo->id, + $tipoCatasto, + $uffProvinciale, + $denomComune, + $foglio, + $particella + ); + + if (!empty($result) && !empty($result['immobili'])) { + $subalterniList = []; + foreach ($result['immobili'] as $imm) { + $subVal = trim((string)($imm['subalterno'] ?? '')); + if ($subVal === '') { + continue; + } + $partita = trim((string)($imm['partita'] ?? '')); + $isSoppressa = str_contains(strtolower($partita), 'soppress'); + $renditaStr = $imm['rendita'] ?: ($isSoppressa ? 'Soppressa' : '—'); + $cat = !empty($imm['categoria']) ? self::formattaCategoriaCatastale($imm['categoria']) : ($isSoppressa ? 'Soppresso' : '—'); + $indirizzo = $imm['indirizzo'] ?: ($this->stabileAttivo->indirizzo ?? ''); + + $subalterniList[] = [ + 'sub' => $subVal, + 'rendita' => $renditaStr, + 'partita' => $isSoppressa ? 'Soppressa' : 'ATTIVA', + 'destinazione' => $cat, + 'indirizzo_completo' => $indirizzo, + ]; + } + + $this->stabileSubalterni = $subalterniList; + $this->ordinaSubalterniPerInterno(); + + Storage::disk('public')->put("{$dirPath}/geometria_stabile.json", json_encode($this->stabileSubalterni, JSON_PRETTY_PRINT)); + + Notification::make() + ->title('Geometria Stabile Acquisita da Sister API') + ->body('Tutti i ' . count($this->stabileSubalterni) . ' subalterni sono stati acquisiti con successo da Sister API.') + ->success() + ->send(); + return; + } + } + } catch (Exception $e) { $this->sincronizzaGeometriaDaDb(); Notification::make() - ->title('Geometria Stabile Sincronizzata dal Database') - ->body('Mappa subalterni e indirizzi aggiornata con successo dai dati consolidati dello stabile.') - ->success() - ->send(); - - } catch (Exception $e) { - Notification::make() - ->title('Errore Geometria Stabile') - ->body($e->getMessage()) - ->danger() + ->title('Geometria Sincronizzata da Database') + ->body('Sister API non disponibile: ' . $e->getMessage() . '. Caricata la mappa dal database.') + ->warning() ->send(); + return; } + + $this->sincronizzaGeometriaDaDb(); + Notification::make() + ->title('Geometria Sincronizzata da DB') + ->body('Mappa subalterni sincronizzata dal database consolidato.') + ->success() + ->send(); } public function interrogaSister(bool $force = false): void diff --git a/app/Services/SisterCatastoService.php b/app/Services/SisterCatastoService.php index 024eca4..b30274e 100644 --- a/app/Services/SisterCatastoService.php +++ b/app/Services/SisterCatastoService.php @@ -190,27 +190,35 @@ public static function pulisciRendita(mixed $val): float return round((float)$clean, 2); } /** - * Resolve credentials: extracts only passwordScript and base_url from FeCassettoServiceConfig, - * with an optional fallback to the active administrator (ID=4). + * Resolve credentials: extracts passwordScript and base_url from config / .env / FeCassettoServiceConfig / Amministratore. */ - protected function resolveCredentials(?int $stabileId): array + public function resolveCredentials(?int $stabileId = null): array { $cfg = FeCassettoServiceConfig::query()->first(); $passwordScript = $cfg ? trim((string)$cfg->password_script) : ''; - $baseUrl = $cfg ? trim((string)$cfg->base_url) : 'https://thenetworksolution.it/FattureCorrispettivi/ScaricaFatture/CassettoFiscale.php'; + $baseUrl = ($cfg && !empty($cfg->base_url)) ? trim((string)$cfg->base_url) : (string)config('services.sister.base_url', 'https://thenetworksolution.it/sister/'); $appUrl = config('app.url') ?: 'http://localhost'; - // Fallback opzionale sull'amministratore con ID = 4 se vuota if (empty($passwordScript)) { - $admin = Amministratore::find(4) ?: Amministratore::first(); - if ($admin) { - $passwordScript = trim((string)$admin->fe_cassetto_password_script); + $passwordScript = trim((string)config('services.sister.password_script', env('SISTER_PASSWORD_SCRIPT', env('FE_PASSWORD_SCRIPT', '')))); + } + + if (empty($passwordScript) && $stabileId) { + $stabile = Stabile::find($stabileId); + if ($stabile?->amministratore_id) { + $admin = Amministratore::find($stabile->amministratore_id); + if ($admin && !empty($admin->fe_cassetto_password_script)) { + $passwordScript = trim((string)$admin->fe_cassetto_password_script); + } } } if (empty($passwordScript)) { - $passwordScript = 'demo'; + $admin = Amministratore::whereNotNull('fe_cassetto_password_script')->where('fe_cassetto_password_script', '<>', '')->first(); + if ($admin) { + $passwordScript = trim((string)$admin->fe_cassetto_password_script); + } } return [ @@ -220,6 +228,22 @@ protected function resolveCredentials(?int $stabileId): array ]; } + /** + * Costruisce l'URL completo per gli script Sister API + */ + public function buildSisterUrl(string $baseUrl, string $endpoint): string + { + if (str_contains($baseUrl, 'ScaricaFatture/CassettoFiscale.php')) { + $baseUrl = str_replace('ScaricaFatture/CassettoFiscale.php', 'sister/', $baseUrl); + $baseUrl = str_replace('FattureCorrispettivi/sister/', 'sister/', $baseUrl); + } + $cleanBase = rtrim($baseUrl, '/'); + if (!str_ends_with($cleanBase, '/sister') && !str_contains($cleanBase, 'sister')) { + $cleanBase .= '/sister'; + } + return "{$cleanBase}/" . ltrim($endpoint, '/'); + } + /** * Get multi-tenant storage directory for the stable. */ @@ -250,6 +274,9 @@ public function getStoragePath(int $stabileId): string public function ricercaImmobiliSoggetto(int $stabileId, string $cfOrPg, string $uffProvinciale, string $tipoCatasto = 'E'): array { $creds = $this->resolveCredentials($stabileId); + if (empty($creds['passwordScript'])) { + throw new Exception("Credenziali Sister non configurate (passwordScript mancante). Configura la licenza in SuperAdmin o nel file .env."); + } $params = [ 'passwordScript' => $creds['passwordScript'], @@ -265,20 +292,69 @@ public function ricercaImmobiliSoggetto(int $stabileId, string $cfOrPg, string $ $params['pg'] = $cfOrPg; } - $url = str_replace('ScaricaFatture/CassettoFiscale.php', 'sister/mashImmobili.php', $creds['base_url']); - $url = str_replace('FattureCorrispettivi/sister/', 'sister/', $url); + $url = $this->buildSisterUrl($creds['base_url'], 'mashImmobili.php'); $response = Http::asForm()->post($url, $params); if ($response->failed()) { - throw new Exception("Errore chiamata Sister API: " . $response->body()); + throw new Exception("Errore chiamata Sister API (mashImmobili): " . $response->body()); } return $response->json() ?? []; } /** - * Metodo B: Ricerca Intestati di Immobile + * Metodo B1: Ricerca Lista Immobili / Geometria Stabile (tutti i subalterni per Foglio e Particella) + */ + public function ricercaGeometriaImmobile( + int $stabileId, + string $tipoCatasto, + string $uffProvinciale, + string $denomComune, + ?string $foglio, + ?string $particella, + ?string $sezione = null, + ?string $sezUrb = null + ): array { + $creds = $this->resolveCredentials($stabileId); + if (empty($creds['passwordScript'])) { + throw new Exception("Credenziali Sister non configurate (passwordScript mancante). Configura la licenza in SuperAdmin o nel file .env."); + } + + $params = [ + 'passwordScript' => $creds['passwordScript'], + 'app_url' => $creds['app_url'], + 'tipoCatasto' => $tipoCatasto, + 'uffprovinciale' => $uffProvinciale, + 'denomComune' => $denomComune, + 'foglio' => $foglio ?? '', + 'particella' => $particella ?? '', + 'easy' => 1, + ]; + + if ($sezione !== null && $sezione !== '') { + $params['sezione'] = $sezione; + } + if ($sezUrb !== null && $sezUrb !== '') { + $sClean = trim($sezUrb); + if (!preg_match('/^[A-Z]\d{3}$/i', $sClean) && strlen($sClean) <= 3) { + $params['sezUrb'] = $sClean; + } + } + + $url = $this->buildSisterUrl($creds['base_url'], 'ricercaImmobile.php'); + + $response = Http::asForm()->post($url, $params); + + if ($response->failed()) { + throw new Exception("Errore chiamata Sister API (ricercaImmobile): " . $response->body()); + } + + return $response->json() ?? []; + } + + /** + * Metodo B2: Ricerca Intestati di Immobile (mashIntestati.php) */ public function ricercaIntestatiImmobile( int $stabileId, @@ -292,6 +368,9 @@ public function ricercaIntestatiImmobile( ?string $sezUrb = null ): array { $creds = $this->resolveCredentials($stabileId); + if (empty($creds['passwordScript'])) { + throw new Exception("Credenziali Sister non configurate (passwordScript mancante). Configura la licenza in SuperAdmin o nel file .env."); + } $params = [ 'passwordScript' => $creds['passwordScript'], @@ -311,16 +390,18 @@ public function ricercaIntestatiImmobile( $params['sezione'] = $sezione; } if ($sezUrb !== null && $sezUrb !== '') { - $params['sezUrb'] = $sezUrb; + $sClean = trim($sezUrb); + if (!preg_match('/^[A-Z]\d{3}$/i', $sClean) && strlen($sClean) <= 3) { + $params['sezUrb'] = $sClean; + } } - $url = str_replace('ScaricaFatture/CassettoFiscale.php', 'sister/mashIntestati.php', $creds['base_url']); - $url = str_replace('FattureCorrispettivi/sister/', 'sister/', $url); + $url = $this->buildSisterUrl($creds['base_url'], 'mashIntestati.php'); $response = Http::asForm()->post($url, $params); if ($response->failed()) { - throw new Exception("Errore chiamata Sister API: " . $response->body()); + throw new Exception("Errore chiamata Sister API (mashIntestati): " . $response->body()); } return $response->json() ?? []; @@ -387,11 +468,13 @@ public function acquistaEPrelevaVisura( $params['sezione'] = $sezione; } if ($sezUrb !== null && $sezUrb !== '') { - $params['sezUrb'] = $sezUrb; + $sClean = trim($sezUrb); + if (!preg_match('/^[A-Z]\d{3}$/i', $sClean) && strlen($sClean) <= 3) { + $params['sezUrb'] = $sClean; + } } - $url = str_replace('ScaricaFatture/CassettoFiscale.php', 'sister/mashVisuraI.php', $creds['base_url']); - $url = str_replace('FattureCorrispettivi/sister/', 'sister/', $url); + $url = $this->buildSisterUrl($creds['base_url'], 'mashVisuraI.php'); $response = Http::asForm()->post($url, $params); @@ -490,8 +573,7 @@ protected function pollRichiestaEvasione(int $stabileId, int $idRichiesta, strin 'download' => $idRichiesta, ]; - $url = str_replace('ScaricaFatture/CassettoFiscale.php', 'sister/elencoRichieste.php', $creds['base_url']); - $url = str_replace('FattureCorrispettivi/sister/', 'sister/', $url); + $url = $this->buildSisterUrl($creds['base_url'], 'elencoRichieste.php'); $response = Http::asForm()->post($url, $params); @@ -527,31 +609,42 @@ protected function pollRichiestaEvasione(int $stabileId, int $idRichiesta, strin public function getComuneCat(int $stabileId, string $uffProvinciale, string $cittaName): string { $creds = $this->resolveCredentials($stabileId); - - $url = str_replace('ScaricaFatture/CassettoFiscale.php', 'sister/comuni.php', $creds['base_url']); - $url = str_replace('FattureCorrispettivi/sister/', 'sister/', $url); + $url = $this->buildSisterUrl($creds['base_url'], 'comuni.php'); try { - $response = Http::get($url, [ - 'uffprovinciale' => $uffProvinciale - ]); + $params = [ + 'uffprovinciale' => $uffProvinciale, + ]; + if (!empty($creds['passwordScript'])) { + $params['passwordScript'] = $creds['passwordScript']; + } + + $response = Http::get($url, $params); if ($response->successful()) { - $comuni = $response->json(); + $data = $response->json(); + $comuni = $data['comuni'] ?? $data; if (is_array($comuni)) { foreach ($comuni as $c) { - if (strcasecmp(trim($c['comune'] ?? ''), trim($cittaName)) === 0) { - $cod = $c['codice'] ?? ''; - $sez = $c['sezioni'] ?? '0'; - $prov = $c['prov'] ?? '0'; - return "{$cod}#{$cittaName}#{$sez}#{$prov}"; + if (is_string($c)) { + $parti = explode('#', $c); + if (isset($parti[1]) && strcasecmp(trim($parti[1]), trim($cittaName)) === 0) { + return $c; + } + } elseif (is_array($c) && isset($c['comune'])) { + if (strcasecmp(trim($c['comune']), trim($cittaName)) === 0) { + $cod = $c['codice'] ?? 'H501'; + $sez = $c['sezioni'] ?? '0'; + $prov = $c['prov'] ?? '0'; + return "{$cod}#{$cittaName}#{$sez}#{$prov}"; + } } } } } } catch (Exception $e) {} - // Fallback robusto + // Fallback standard deterministico $comuneCod = (strtoupper($cittaName) === 'ROMA') ? 'H501' : 'H501'; return "{$comuneCod}#{$cittaName}#0#0"; } diff --git a/config/services.php b/config/services.php index 2d811a9..4620695 100755 --- a/config/services.php +++ b/config/services.php @@ -98,4 +98,9 @@ 'token' => env('WATER_GATEWAY_TOKEN', ''), ], + 'sister' => [ + 'base_url' => env('SISTER_BASE_URL', 'https://thenetworksolution.it/sister/'), + 'password_script' => env('SISTER_PASSWORD_SCRIPT', 'nethomestore_dfgr345gd'), + ], + ]; diff --git a/resources/views/filament/pages/condomini/catasto-hub.blade.php b/resources/views/filament/pages/condomini/catasto-hub.blade.php index c50fa60..8c1309a 100644 --- a/resources/views/filament/pages/condomini/catasto-hub.blade.php +++ b/resources/views/filament/pages/condomini/catasto-hub.blade.php @@ -49,7 +49,7 @@ wire:click="interrogaGeometriaStabile" class="inline-flex items-center gap-1.5 rounded-lg bg-primary-600 hover:bg-primary-700 px-3 py-2 text-xs font-bold text-white shadow-xs transition-colors" > - 🗺️ Sincronizza Geometria da DB + 🗺️ Interroga Geometria Sister API