diff --git a/app/Filament/Pages/Condomini/LettureServiziArchivio.php b/app/Filament/Pages/Condomini/LettureServiziArchivio.php index 52463d6..b5976d5 100644 --- a/app/Filament/Pages/Condomini/LettureServiziArchivio.php +++ b/app/Filament/Pages/Condomini/LettureServiziArchivio.php @@ -325,8 +325,8 @@ public function table(Table $table): Table ->color(function ($state, StabileServizioLettura $record): string { return match ((string) data_get($record->raw, 'consistency_check.status', '')) { 'warning' => 'warning', - 'danger' => 'danger', - default => 'gray', + 'danger' => 'danger', + default => 'gray', }; }) ->wrap() @@ -600,15 +600,15 @@ public function table(Table $table): Table TextInput::make('rilevatore_nome')->label('Nominativo rilevatore')->maxLength(191), Textarea::make('motivo')->label('Nota riassegnazione')->rows(3)->maxLength(1000), ]) - ->fillForm(fn(StabileServizioLettura $record): array => [ + ->fillForm(fn(StabileServizioLettura $record): array=> [ 'unita_immobiliare_id' => $record->unita_immobiliare_id, 'rilevatore_tipo' => (string) ($record->rilevatore_tipo ?? ''), 'rilevatore_nome' => (string) ($record->rilevatore_nome ?? ''), 'motivo' => '', ]) ->action(function (StabileServizioLettura $record, array $data): void { - $raw = is_array($record->raw ?? null) ? $record->raw : []; - $reassignments = is_array($raw['reassignments'] ?? null) ? $raw['reassignments'] : []; + $raw = is_array($record->raw ?? null) ? $record->raw : []; + $reassignments = is_array($raw['reassignments'] ?? null) ? $raw['reassignments'] : []; $reassignments[] = [ 'from_unita_immobiliare_id' => (int) ($record->getOriginal('unita_immobiliare_id') ?? 0) ?: null, 'to_unita_immobiliare_id' => (int) ($data['unita_immobiliare_id'] ?? 0) ?: null, @@ -618,7 +618,7 @@ public function table(Table $table): Table 'changed_by' => Auth::id(), 'changed_at' => now()->toIso8601String(), ]; - $raw['reassignments'] = $reassignments; + $raw['reassignments'] = $reassignments; $raw['reader_assignment'] = [ 'user_id' => null, 'name' => trim((string) ($data['rilevatore_nome'] ?? '')) ?: null, @@ -626,12 +626,12 @@ public function table(Table $table): Table ]; $record->fill([ - 'unita_immobiliare_id' => (int) ($data['unita_immobiliare_id'] ?? 0) ?: null, - 'rilevatore_tipo' => trim((string) ($data['rilevatore_tipo'] ?? '')) ?: null, - 'rilevatore_nome' => trim((string) ($data['rilevatore_nome'] ?? '')) ?: null, - 'lettura_precedente_valore' => null, + 'unita_immobiliare_id' => (int) ($data['unita_immobiliare_id'] ?? 0) ?: null, + 'rilevatore_tipo' => trim((string) ($data['rilevatore_tipo'] ?? '')) ?: null, + 'rilevatore_nome' => trim((string) ($data['rilevatore_nome'] ?? '')) ?: null, + 'lettura_precedente_valore' => null, 'lettura_precedente_foto_path' => null, - 'raw' => $raw, + 'raw' => $raw, ]); $record->save(); $this->hydrateReadingWithPreviousData($record); @@ -659,7 +659,7 @@ public function table(Table $table): Table TextInput::make('rilevatore_nome')->label('Nominativo rilevatore')->maxLength(191), Textarea::make('motivo')->label('Motivo spostamento')->rows(3)->maxLength(1000), ]) - ->fillForm(fn(StabileServizioLettura $record): array => [ + ->fillForm(fn(StabileServizioLettura $record): array=> [ 'stabile_servizio_id' => $record->stabile_servizio_id, 'rilevatore_tipo' => (string) ($record->rilevatore_tipo ?? ''), 'rilevatore_nome' => (string) ($record->rilevatore_nome ?? ''), @@ -668,7 +668,7 @@ public function table(Table $table): Table ->visible(fn(StabileServizioLettura $record): bool => strtolower(trim((string) ($record->servizio?->tipo ?? ''))) === 'acqua') ->action(function (StabileServizioLettura $record, array $data): void { $targetServiceId = (int) ($data['stabile_servizio_id'] ?? 0); - $targetService = StabileServizio::query() + $targetService = StabileServizio::query() ->where('id', $targetServiceId) ->where('stabile_id', (int) $record->stabile_id) ->where('tipo', 'acqua') @@ -679,20 +679,20 @@ public function table(Table $table): Table return; } - $raw = is_array($record->raw ?? null) ? $record->raw : []; - $movements = is_array($raw['common_meter_movements'] ?? null) ? $raw['common_meter_movements'] : []; + $raw = is_array($record->raw ?? null) ? $record->raw : []; + $movements = is_array($raw['common_meter_movements'] ?? null) ? $raw['common_meter_movements'] : []; $movements[] = [ - 'from_stabile_servizio_id' => (int) ($record->getOriginal('stabile_servizio_id') ?? 0) ?: null, - 'to_stabile_servizio_id' => (int) $targetService->id, - 'from_unita_immobiliare_id'=> (int) ($record->getOriginal('unita_immobiliare_id') ?? 0) ?: null, - 'to_unita_immobiliare_id' => null, - 'note' => trim((string) ($data['motivo'] ?? '')), - 'changed_by' => Auth::id(), - 'changed_at' => now()->toIso8601String(), + 'from_stabile_servizio_id' => (int) ($record->getOriginal('stabile_servizio_id') ?? 0) ?: null, + 'to_stabile_servizio_id' => (int) $targetService->id, + 'from_unita_immobiliare_id' => (int) ($record->getOriginal('unita_immobiliare_id') ?? 0) ?: null, + 'to_unita_immobiliare_id' => null, + 'note' => trim((string) ($data['motivo'] ?? '')), + 'changed_by' => Auth::id(), + 'changed_at' => now()->toIso8601String(), ]; $raw['common_meter_movements'] = $movements; - $raw['reader_assignment'] = [ + $raw['reader_assignment'] = [ 'user_id' => null, 'name' => trim((string) ($data['rilevatore_nome'] ?? '')) ?: (trim((string) ($record->rilevatore_nome ?? '')) ?: null), 'type' => trim((string) ($data['rilevatore_tipo'] ?? '')) ?: (trim((string) ($record->rilevatore_tipo ?? '')) ?: null), @@ -705,15 +705,15 @@ public function table(Table $table): Table ]; $record->fill([ - 'stabile_servizio_id' => (int) $targetService->id, - 'unita_immobiliare_id' => null, - 'fornitore_id' => $targetService->fornitore_id, - 'rilevatore_tipo' => trim((string) ($data['rilevatore_tipo'] ?? '')) ?: $record->rilevatore_tipo, - 'rilevatore_nome' => trim((string) ($data['rilevatore_nome'] ?? '')) ?: $record->rilevatore_nome, - 'tipologia_lettura' => 'autolettura_contatore_generale', - 'lettura_precedente_valore' => null, + 'stabile_servizio_id' => (int) $targetService->id, + 'unita_immobiliare_id' => null, + 'fornitore_id' => $targetService->fornitore_id, + 'rilevatore_tipo' => trim((string) ($data['rilevatore_tipo'] ?? '')) ?: $record->rilevatore_tipo, + 'rilevatore_nome' => trim((string) ($data['rilevatore_nome'] ?? '')) ?: $record->rilevatore_nome, + 'tipologia_lettura' => 'autolettura_contatore_generale', + 'lettura_precedente_valore' => null, 'lettura_precedente_foto_path' => null, - 'raw' => $raw, + 'raw' => $raw, ]); $record->save(); $this->hydrateReadingWithPreviousData($record); @@ -874,9 +874,9 @@ private function getServiziOptions(): array ->orderBy('nome') ->get(['id', 'tipo', 'nome', 'contatore_matricola', 'meta']) ->mapWithKeys(function (StabileServizio $s): array { - $tipo = strtoupper(trim((string) ($s->tipo ?? ''))); - $nome = trim((string) ($s->nome ?? '')); - $matr = trim((string) ($s->contatore_matricola ?? '')); + $tipo = strtoupper(trim((string) ($s->tipo ?? ''))); + $nome = trim((string) ($s->nome ?? '')); + $matr = trim((string) ($s->contatore_matricola ?? '')); $asset = trim((string) data_get($s->meta, 'common_asset_label', '')); $label = $nome !== '' ? $nome : ($tipo !== '' ? $tipo : ('Servizio #' . $s->id)); @@ -1084,11 +1084,11 @@ private function getCommonWaterServiceOptions(int $stabileId): array ->orderBy('contatore_matricola') ->get(['id', 'nome', 'contatore_matricola', 'meta']) ->mapWithKeys(function (StabileServizio $service): array { - $name = trim((string) ($service->nome ?? '')) ?: ('Servizio #' . (int) $service->id); - $asset = trim((string) data_get($service->meta, 'common_asset_label', '')); - $servedArea = trim((string) data_get($service->meta, 'served_area_label', '')); + $name = trim((string) ($service->nome ?? '')) ?: ('Servizio #' . (int) $service->id); + $asset = trim((string) data_get($service->meta, 'common_asset_label', '')); + $servedArea = trim((string) data_get($service->meta, 'served_area_label', '')); $counterScope = trim((string) data_get($service->meta, 'counter_scope', '')); - $matricola = trim((string) ($service->contatore_matricola ?? '')); + $matricola = trim((string) ($service->contatore_matricola ?? '')); $parts = array_filter([ $name, diff --git a/app/Filament/Pages/Condomini/ServiziStabileArchivio.php b/app/Filament/Pages/Condomini/ServiziStabileArchivio.php index ec75afa..437aa9f 100644 --- a/app/Filament/Pages/Condomini/ServiziStabileArchivio.php +++ b/app/Filament/Pages/Condomini/ServiziStabileArchivio.php @@ -637,16 +637,16 @@ private function getServiceTypeOptions(): array private function getCommonAssetScopeOptions(): array { return [ - 'locale' => 'Locale', - 'spazio' => 'Spazio comune', - 'impianto' => 'Impianto', - 'area_esterna' => 'Area esterna / giardino', - 'copertura' => 'Terrazzo / copertura', - 'accesso' => 'Portone / accesso', - 'servizio' => 'Servizio comune', - 'sicurezza' => 'Sicurezza / antincendio', - 'amministrativo'=> 'Privacy / assicurazione / studio', - 'altro' => 'Altro', + 'locale' => 'Locale', + 'spazio' => 'Spazio comune', + 'impianto' => 'Impianto', + 'area_esterna' => 'Area esterna / giardino', + 'copertura' => 'Terrazzo / copertura', + 'accesso' => 'Portone / accesso', + 'servizio' => 'Servizio comune', + 'sicurezza' => 'Sicurezza / antincendio', + 'amministrativo' => 'Privacy / assicurazione / studio', + 'altro' => 'Altro', ]; } @@ -657,12 +657,12 @@ private function getAllocationScopeOptions(): array { return [ 'tutti_millesimi' => 'Tutti per millesimi', - 'condomini_utilizzatori' => 'Condomini utilizzatori', - 'inquilini_utilizzatori' => 'Inquilini utilizzatori', - 'condomini_inquilini_utilizzatori'=> 'Condomini + inquilini utilizzatori', - 'rimborso_spese' => 'Rimborso spese uso bene comune', - 'gestione_studio' => 'Gestione studio / amministrazione', - 'altro' => 'Altro criterio', + 'condomini_utilizzatori' => 'Condomini utilizzatori', + 'inquilini_utilizzatori' => 'Inquilini utilizzatori', + 'condomini_inquilini_utilizzatori' => 'Condomini + inquilini utilizzatori', + 'rimborso_spese' => 'Rimborso spese uso bene comune', + 'gestione_studio' => 'Gestione studio / amministrazione', + 'altro' => 'Altro criterio', ]; } @@ -672,11 +672,11 @@ private function getAllocationScopeOptions(): array private function getFiscalScopeOptions(): array { return [ - 'spesa_condominiale' => 'Spesa condominiale', - 'rimborso_non_fiscale' => 'Rimborso spese non fiscale', - 'da_fatturare' => 'Da fatturare', - 'polizza_o_servizio' => 'Polizza / servizio', - 'non_applicabile' => 'Non applicabile', + 'spesa_condominiale' => 'Spesa condominiale', + 'rimborso_non_fiscale' => 'Rimborso spese non fiscale', + 'da_fatturare' => 'Da fatturare', + 'polizza_o_servizio' => 'Polizza / servizio', + 'non_applicabile' => 'Non applicabile', ]; } diff --git a/app/Filament/Pages/Condomini/TabelleMillesimaliArchivio.php b/app/Filament/Pages/Condomini/TabelleMillesimaliArchivio.php index 3510930..4a3ba4d 100644 --- a/app/Filament/Pages/Condomini/TabelleMillesimaliArchivio.php +++ b/app/Filament/Pages/Condomini/TabelleMillesimaliArchivio.php @@ -177,9 +177,9 @@ protected function getTableQuery(): Builder return TabellaMillesimale::query()->whereRaw('1 = 0'); } - $orderColumn = Schema::hasColumn('tabelle_millesimali', 'ordine_visualizzazione') - ? 'ordine_visualizzazione' - : (Schema::hasColumn('tabelle_millesimali', 'nord') ? 'nord' : (Schema::hasColumn('tabelle_millesimali', 'ordinamento') ? 'ordinamento' : 'id')); + $orderColumn = Schema::hasColumn('tabelle_millesimali', 'nord') + ? 'nord' + : (Schema::hasColumn('tabelle_millesimali', 'ordine_visualizzazione') ? 'ordine_visualizzazione' : (Schema::hasColumn('tabelle_millesimali', 'ordinamento') ? 'ordinamento' : 'id')); return TabellaMillesimale::query() ->where('stabile_id', $activeStabileId) @@ -326,13 +326,13 @@ public function table(Table $table): Table ]) ->columns([ TextColumn::make( - Schema::hasColumn('tabelle_millesimali', 'ordine_visualizzazione') - ? 'ordine_visualizzazione' - : 'ordinamento' + Schema::hasColumn('tabelle_millesimali', 'nord') + ? 'nord' + : (Schema::hasColumn('tabelle_millesimali', 'ordine_visualizzazione') ? 'ordine_visualizzazione' : 'ordinamento') ) - ->label('Ord.') + ->label('Nord') ->sortable() - ->toggleable(isToggledHiddenByDefault: true), + ->toggleable(), TextColumn::make('codice_tabella') ->label('Codice') @@ -614,7 +614,7 @@ protected function loadTabelle(): void ->ordinato(); $this->tabelle = $q - ->get(['id', 'codice_tabella', 'nome_tabella', 'denominazione', 'tipo_tabella', 'tipo_calcolo', 'totale_millesimi', 'ordinamento', 'meta_legacy']) + ->get(['id', 'codice_tabella', 'nome_tabella', 'denominazione', 'tipo_tabella', 'tipo_calcolo', 'totale_millesimi', 'ordinamento', 'ordine_visualizzazione', 'nord', 'meta_legacy']) ->map(function (TabellaMillesimale $t) { $codice = $t->codice_tabella ?: ($t->nome_tabella ?: ('TAB ' . $t->id)); $nome = $t->denominazione ?: ($t->nome_tabella_millesimale ?: ($t->nome_tabella ?: 'Tabella')); @@ -634,11 +634,12 @@ protected function loadTabelle(): void 'id' => (int) $t->id, 'codice' => $codice, 'nome' => $nome, + 'nord' => $this->resolveNordValue($t), 'tipo' => $tipoLabel, 'calcolo' => $calcoloLabel, 'is_consumo' => $isConsumo, 'totale' => is_numeric($t->totale_millesimi) ? (float) $t->totale_millesimi : null, - 'ordinamento' => (int) ($t->ordinamento ?? 999999), + 'ordinamento' => $this->resolveNordValue($t) ?? (int) ($t->ordine_visualizzazione ?? $t->ordinamento ?? 999999), 'is_bilanciata' => (bool) ($t->is_bilanciata ?? false), 'preventivo' => is_numeric($prev) ? (float) $prev : null, 'consuntivo' => is_numeric($cons) ? (float) $cons : null, @@ -646,6 +647,23 @@ protected function loadTabelle(): void }) ->values() ->all(); + + usort($this->tabelle, static function (array $left, array $right): int { + $leftNord = is_numeric($left['ordinamento'] ?? null) ? (int) $left['ordinamento'] : 999999; + $rightNord = is_numeric($right['ordinamento'] ?? null) ? (int) $right['ordinamento'] : 999999; + + if ($leftNord !== $rightNord) { + return $leftNord <=> $rightNord; + } + + $leftTipo = (string) ($left['tipo'] ?? ''); + $rightTipo = (string) ($right['tipo'] ?? ''); + if ($leftTipo !== $rightTipo) { + return strnatcasecmp($leftTipo, $rightTipo); + } + + return strnatcasecmp((string) ($left['codice'] ?? ''), (string) ($right['codice'] ?? '')); + }); } protected function pickTabellaId(?int $candidate): ?int @@ -1075,7 +1093,6 @@ private function formatCodiceUnita(?string $codice): ?string return null; } - $prefix = is_string($this->codiceStabile) ? trim($this->codiceStabile) : ''; if ($prefix !== '') { $pattern = '/^' . preg_quote($prefix, '/') . '[\s\-\/]+/'; $codice = preg_replace($pattern, '', $codice) ?? $codice; @@ -1338,4 +1355,16 @@ private function isConsumoCalcolo(?string $calcolo): bool $c = strtolower(trim((string) ($calcolo ?? ''))); return in_array($c, ['acqua', 'a', 'consumo', 'c', 'a_consumo'], true); } + + private function resolveNordValue(TabellaMillesimale $t): ?int + { + foreach (['nord', 'ordine_visualizzazione', 'ordinamento'] as $field) { + $value = $t->{$field} ?? null; + if (is_numeric($value)) { + return (int) $value; + } + } + + return null; + } } diff --git a/app/Filament/Pages/Contabilita/FattureElettronicheP7mRicevute.php b/app/Filament/Pages/Contabilita/FattureElettronicheP7mRicevute.php index ec4e605..ea4c1d2 100644 --- a/app/Filament/Pages/Contabilita/FattureElettronicheP7mRicevute.php +++ b/app/Filament/Pages/Contabilita/FattureElettronicheP7mRicevute.php @@ -79,7 +79,7 @@ public function getActiveStabileDestinationSummaryProperty(): string } $summary = $this->getActiveStabileLabelProperty(); - $cf = $this->resolveStabileSoggettoCf($stabile); + $cf = $this->resolveStabileSoggettoCf($stabile); if ($cf !== '') { $summary .= "\nCodice fiscale soggetto usato per lo scarico: {$cf}"; @@ -355,9 +355,9 @@ private function resolveStabileSoggettoCf(Stabile $stabile): string private function isLikelyTechnicalFeShell(Stabile $stabile): bool { - $stabileCf = $this->resolveStabileSoggettoCf($stabile); - $adminCf = strtoupper(trim((string) ($stabile->amministratore?->codice_fiscale_studio ?? ''))); - $code = strtoupper(trim((string) ($stabile->codice_stabile ?? ''))); + $stabileCf = $this->resolveStabileSoggettoCf($stabile); + $adminCf = strtoupper(trim((string) ($stabile->amministratore?->codice_fiscale_studio ?? ''))); + $code = strtoupper(trim((string) ($stabile->codice_stabile ?? ''))); $legacyCode = trim((string) ($stabile->cod_stabile ?? '')); return $stabileCf !== '' diff --git a/app/Filament/Pages/Supporto/TicketAcqua.php b/app/Filament/Pages/Supporto/TicketAcqua.php index d4bfb26..78bbc30 100644 --- a/app/Filament/Pages/Supporto/TicketAcqua.php +++ b/app/Filament/Pages/Supporto/TicketAcqua.php @@ -943,13 +943,13 @@ private function resolveUnitSearchNames(UnitaImmobiliare $unita): array */ private function resolveRelevantHistoricNames(UnitaImmobiliare $unita): array { - $today = now()->toDateString(); + $today = now()->toDateString(); $historic = collect($unita->nominativiStorici ?? []); $current = $historic ->filter(function ($item) use ($today): bool { $start = trim((string) ($item->data_inizio ?? '')); - $end = trim((string) ($item->data_fine ?? '')); + $end = trim((string) ($item->data_fine ?? '')); return ($start === '' || $start <= $today) && ($end === '' || $end >= $today); diff --git a/app/Filament/Pages/Supporto/TicketAcquaGenerale.php b/app/Filament/Pages/Supporto/TicketAcquaGenerale.php index 628922b..695f852 100644 --- a/app/Filament/Pages/Supporto/TicketAcquaGenerale.php +++ b/app/Filament/Pages/Supporto/TicketAcquaGenerale.php @@ -920,10 +920,10 @@ private function buildReadingConsistencyCheck(int $servizioId, ?int $unitaId, fl private function formatCounterScopeLabel(string $value): string { return match (strtolower(trim($value))) { - 'generale' => 'generale', + 'generale' => 'generale', 'particolare' => 'particolare', - 'assente' => 'senza contatore', - default => trim($value) !== '' ? trim($value) : 'n/d', + 'assente' => 'senza contatore', + default => trim($value) !== '' ? trim($value) : 'n/d', }; } diff --git a/app/Filament/Pages/Supporto/TicketAcquaLight.php b/app/Filament/Pages/Supporto/TicketAcquaLight.php index 110b02f..7771f4a 100644 --- a/app/Filament/Pages/Supporto/TicketAcquaLight.php +++ b/app/Filament/Pages/Supporto/TicketAcquaLight.php @@ -40,9 +40,9 @@ private function resetLightUnitSelection(): void { $user = Auth::user(); - $this->unitaId = null; - $this->unitaSearch = ''; - $this->previousReading = null; + $this->unitaId = null; + $this->unitaSearch = ''; + $this->previousReading = null; $this->suggestedReaderName = null; if ($user instanceof User) { diff --git a/app/Providers/Filament/AdminFilamentPanelProvider.php b/app/Providers/Filament/AdminFilamentPanelProvider.php index 70b3e7d..af9e3ed 100644 --- a/app/Providers/Filament/AdminFilamentPanelProvider.php +++ b/app/Providers/Filament/AdminFilamentPanelProvider.php @@ -51,7 +51,6 @@ public function panel(Panel $panel): Panel ->renderHook(PanelsRenderHook::HEAD_END, fn() => view('filament.components.legacy-admin-assets')) ->renderHook(PanelsRenderHook::TOPBAR_LOGO_AFTER, fn() => view('filament.components.topbar-context')) ->renderHook(PanelsRenderHook::USER_MENU_BEFORE, fn() => view('filament.components.topbar-icons')) - ->renderHook(PanelsRenderHook::FOOTER, fn() => view('filament.components.footer')) ->navigationItems([ NavigationItem::make('Rubrica Unica') ->group('NetGescon') @@ -133,7 +132,7 @@ public function panel(Panel $panel): Panel ]); } - private function resolveSupplierCatalogUrl(): string + protected function resolveSupplierCatalogUrl(): string { $user = Auth::user(); diff --git a/app/Services/Consumi/ConsumiAcquaIngestionService.php b/app/Services/Consumi/ConsumiAcquaIngestionService.php index a871010..cc88c61 100644 --- a/app/Services/Consumi/ConsumiAcquaIngestionService.php +++ b/app/Services/Consumi/ConsumiAcquaIngestionService.php @@ -1,5 +1,4 @@ consumo_raw ?? null) ? trim((string) $fattura->consumo_raw) : ''; + $storedRaw = is_string($fattura->consumo_raw ?? null) ? trim((string) $fattura->consumo_raw) : ''; if ($storedRaw !== '') { $decoded = json_decode($storedRaw, true); if (is_array($decoded) && (($decoded['type'] ?? null) === 'acqua')) { @@ -51,13 +50,13 @@ public function ingest( $parsed['consumi'] = $storedPayload['consumi']; } - $codici = is_array($parsed['codici'] ?? null) ? $parsed['codici'] : []; + $codici = is_array($parsed['codici'] ?? null) ? $parsed['codici'] : []; $contatore = is_array($parsed['contatore'] ?? null) ? $parsed['contatore'] : []; - $consumi = is_array($parsed['consumi'] ?? null) ? $parsed['consumi'] : []; + $consumi = is_array($parsed['consumi'] ?? null) ? $parsed['consumi'] : []; $matricola = is_string($contatore['matricola'] ?? null) ? trim((string) $contatore['matricola']) : ''; - $utenza = is_string($codici['utenza'] ?? null) ? trim((string) $codici['utenza']) : ''; - $cliente = is_string($codici['cliente'] ?? null) ? trim((string) $codici['cliente']) : ''; + $utenza = is_string($codici['utenza'] ?? null) ? trim((string) $codici['utenza']) : ''; + $cliente = is_string($codici['cliente'] ?? null) ? trim((string) $codici['cliente']) : ''; $contratto = is_string($codici['contratto'] ?? null) ? trim((string) $codici['contratto']) : ''; $norm = static function (?string $value): string { @@ -82,13 +81,13 @@ public function ingest( (int) ($fattura->fornitore_id ?: 0) ?: null, 'Parser acqua: dati non trovati', 'FE #' . (int) $fattura->id . ' (' . ($fattura->sdi_file ?? 'n/d') . ")\n" - . ($error !== '' ? ('Errore: ' . $error . "\n") : '') - . 'Nessun codice utenza/cliente/contratto, nessuna matricola contatore e nessun periodo consumo rilevato.', + . ($error !== '' ? ('Errore: ' . $error . "\n") : '') + . 'Nessun codice utenza/cliente/contratto, nessuna matricola contatore e nessun periodo consumo rilevato.', ) ? 1 : 0; } return [ - 'status' => 'no-data', + 'status' => 'no-data', 'tickets' => $tickets, 'message' => $error !== '' ? $error : 'Dati acqua non trovati nel PDF', ]; @@ -107,22 +106,22 @@ public function ingest( // Mismatch detection: se il servizio ha già un identificativo e il PDF ne porta un altro, apri ticket e non agganciare. $mismatch = false; - $why = []; + $why = []; if (is_string($servizio->contatore_matricola) && $servizio->contatore_matricola !== '' && $matricola !== '' && $servizio->contatore_matricola !== $matricola) { $mismatch = true; - $why[] = 'matricola diversa (servizio ' . $servizio->contatore_matricola . ' vs PDF ' . $matricola . ')'; + $why[] = 'matricola diversa (servizio ' . $servizio->contatore_matricola . ' vs PDF ' . $matricola . ')'; } if (is_string($servizio->codice_utenza) && $servizio->codice_utenza !== '' && $utenza !== '' && $servizio->codice_utenza !== $utenza) { $mismatch = true; - $why[] = 'utenza diversa (servizio ' . $servizio->codice_utenza . ' vs PDF ' . $utenza . ')'; + $why[] = 'utenza diversa (servizio ' . $servizio->codice_utenza . ' vs PDF ' . $utenza . ')'; } if (is_string($servizio->codice_cliente) && $servizio->codice_cliente !== '' && $cliente !== '' && $servizio->codice_cliente !== $cliente) { $mismatch = true; - $why[] = 'cliente diverso (servizio ' . $servizio->codice_cliente . ' vs PDF ' . $cliente . ')'; + $why[] = 'cliente diverso (servizio ' . $servizio->codice_cliente . ' vs PDF ' . $cliente . ')'; } if (is_string($servizio->codice_contratto) && $servizio->codice_contratto !== '' && $contratto !== '' && $servizio->codice_contratto !== $contratto) { $mismatch = true; - $why[] = 'contratto diverso (servizio ' . $servizio->codice_contratto . ' vs PDF ' . $contratto . ')'; + $why[] = 'contratto diverso (servizio ' . $servizio->codice_contratto . ' vs PDF ' . $contratto . ')'; } if ($mismatch && $createTicketOnMismatch) { $tickets += $this->openTicket( @@ -147,20 +146,20 @@ public function ingest( ->get(); $targetMatricola = $norm($matricola); - $targetUtenza = $norm($utenza); - $targetCliente = $norm($cliente); + $targetUtenza = $norm($utenza); + $targetCliente = $norm($cliente); $targetContratto = $norm($contratto); - $best = null; + $best = null; $bestScore = 0; - $bestTie = 0; + $bestTie = 0; foreach ($candidates as $cand) { $score = 0; $candMatricola = $norm(is_string($cand->contatore_matricola) ? $cand->contatore_matricola : null); - $candUtenza = $norm(is_string($cand->codice_utenza) ? $cand->codice_utenza : null); - $candCliente = $norm(is_string($cand->codice_cliente) ? $cand->codice_cliente : null); + $candUtenza = $norm(is_string($cand->codice_utenza) ? $cand->codice_utenza : null); + $candCliente = $norm(is_string($cand->codice_cliente) ? $cand->codice_cliente : null); $candContratto = $norm(is_string($cand->codice_contratto) ? $cand->codice_contratto : null); if ($targetMatricola !== '' && $candMatricola !== '' && $targetMatricola === $candMatricola) { @@ -177,9 +176,9 @@ public function ingest( } if ($score > $bestScore) { - $best = $cand; + $best = $cand; $bestScore = $score; - $bestTie = 0; + $bestTie = 0; } elseif ($score > 0 && $score === $bestScore) { $bestTie++; } @@ -193,8 +192,8 @@ public function ingest( (int) ($fattura->fornitore_id ?: 0) ?: null, 'Parser acqua: utenza ambigua', 'FE #' . (int) $fattura->id . ' (' . ($fattura->sdi_file ?? 'n/d') . ")\n" - . 'Più utenze acqua compatibili con gli identificativi del PDF. ' . - 'Matricola=' . ($matricola !== '' ? $matricola : 'n/d') . ', Utenza=' . ($utenza !== '' ? $utenza : 'n/d') . ', Cliente=' . ($cliente !== '' ? $cliente : 'n/d') . ', Contratto=' . ($contratto !== '' ? $contratto : 'n/d'), + . 'Più utenze acqua compatibili con gli identificativi del PDF. ' . + 'Matricola=' . ($matricola !== '' ? $matricola : 'n/d') . ', Utenza=' . ($utenza !== '' ? $utenza : 'n/d') . ', Cliente=' . ($cliente !== '' ? $cliente : 'n/d') . ', Contratto=' . ($contratto !== '' ? $contratto : 'n/d'), ) ? 1 : 0; } @@ -216,16 +215,16 @@ public function ingest( (int) ($fattura->fornitore_id ?: 0) ?: null, 'Parser acqua: utenza non riconosciuta', 'FE #' . (int) $fattura->id . ' (' . ($fattura->sdi_file ?? 'n/d') . ")\n" - . 'Identificativi PDF non agganciati a nessuna utenza acqua esistente. ' . - 'Matricola=' . ($matricola !== '' ? $matricola : 'n/d') . ', Utenza=' . ($utenza !== '' ? $utenza : 'n/d') . ', Cliente=' . ($cliente !== '' ? $cliente : 'n/d') . ', Contratto=' . ($contratto !== '' ? $contratto : 'n/d'), + . 'Identificativi PDF non agganciati a nessuna utenza acqua esistente. ' . + 'Matricola=' . ($matricola !== '' ? $matricola : 'n/d') . ', Utenza=' . ($utenza !== '' ? $utenza : 'n/d') . ', Cliente=' . ($cliente !== '' ? $cliente : 'n/d') . ', Contratto=' . ($contratto !== '' ? $contratto : 'n/d'), ) ? 1 : 0; } $servizio = new StabileServizio([ 'stabile_id' => $stabileId, - 'tipo' => 'acqua', - 'nome' => $name, - 'attivo' => true, + 'tipo' => 'acqua', + 'nome' => $name, + 'attivo' => true, ]); } } @@ -263,36 +262,36 @@ public function ingest( } foreach ($consumi as $c) { - $dal = is_string($c['dal'] ?? null) ? (string) $c['dal'] : null; - $al = is_string($c['al'] ?? null) ? (string) $c['al'] : null; - $val = isset($c['valore']) && is_numeric($c['valore']) ? (float) $c['valore'] : null; + $dal = is_string($c['dal'] ?? null) ? (string) $c['dal'] : null; + $al = is_string($c['al'] ?? null) ? (string) $c['al'] : null; + $val = isset($c['valore']) && is_numeric($c['valore']) ? (float) $c['valore'] : null; $unita = is_string($c['unita'] ?? null) ? trim((string) $c['unita']) : ''; - $tipo = is_string($c['tipologia_lettura'] ?? null) ? trim((string) $c['tipologia_lettura']) : null; + $tipo = is_string($c['tipologia_lettura'] ?? null) ? trim((string) $c['tipologia_lettura']) : null; $lettura = StabileServizioLettura::query()->firstOrNew([ - 'stabile_id' => $stabileId, - 'stabile_servizio_id' => (int) $servizio->id, + 'stabile_id' => $stabileId, + 'stabile_servizio_id' => (int) $servizio->id, 'fattura_elettronica_id' => (int) $fattura->id, - 'periodo_dal' => $dal, - 'periodo_al' => $al, + 'periodo_dal' => $dal, + 'periodo_al' => $al, ]); $isNew = ! $lettura->exists; $lettura->fill([ - 'fornitore_id' => (int) ($fattura->fornitore_id ?: 0) ?: null, - 'voce_spesa_id' => $voceSpesaId ?: ($servizio->voce_spesa_id ? (int) $servizio->voce_spesa_id : null), + 'fornitore_id' => (int) ($fattura->fornitore_id ?: 0) ?: null, + 'voce_spesa_id' => $voceSpesaId ?: ($servizio->voce_spesa_id ? (int) $servizio->voce_spesa_id : null), 'tipologia_lettura' => $tipo, - 'consumo_valore' => $val, - 'consumo_unita' => $unita !== '' ? $unita : 'mc', - 'importo_totale' => $importo, - 'raw' => [ - 'source' => 'pdf_ocr', - 'codici' => $parsed['codici'] ?? null, + 'consumo_valore' => $val, + 'consumo_unita' => $unita !== '' ? $unita : 'mc', + 'importo_totale' => $importo, + 'raw' => [ + 'source' => 'pdf_ocr', + 'codici' => $parsed['codici'] ?? null, 'contatore' => $parsed['contatore'] ?? null, - 'consumo' => $c, + 'consumo' => $c, ], - 'created_by' => $userId > 0 ? $userId : null, + 'created_by' => $userId > 0 ? $userId : null, ]); $lettura->save(); @@ -305,11 +304,11 @@ public function ingest( } return [ - 'status' => 'ok', - 'servizio_id' => (int) $servizio->id, + 'status' => 'ok', + 'servizio_id' => (int) $servizio->id, 'created_letture' => $created, 'updated_letture' => $updated, - 'tickets' => $tickets, + 'tickets' => $tickets, ]; } @@ -346,14 +345,14 @@ private function openTicket(int $stabileId, int $userId, ?int $fornitoreId, stri } Ticket::query()->create([ - 'stabile_id' => $stabileId, - 'aperto_da_user_id' => $userId > 0 ? $userId : 1, - 'categoria_ticket_id' => (int) $cat->id, + 'stabile_id' => $stabileId, + 'aperto_da_user_id' => $userId > 0 ? $userId : 1, + 'categoria_ticket_id' => (int) $cat->id, 'assegnato_a_fornitore_id' => $fornitoreId, - 'titolo' => $title, - 'descrizione' => $body, - 'stato' => 'Aperto', - 'priorita' => 'Media', + 'titolo' => $title, + 'descrizione' => $body, + 'stato' => 'Aperto', + 'priorita' => 'Media', ]); return true; diff --git a/docs/ai/SESSION_HANDOFF.md b/docs/ai/SESSION_HANDOFF.md index 273fc9b..746c4a5 100644 --- a/docs/ai/SESSION_HANDOFF.md +++ b/docs/ai/SESSION_HANDOFF.md @@ -1,3 +1,73 @@ +# SESSION HANDOFF - 2026-04-13 / 2026-04-14 + +## Stato operativo reale alla chiusura sessione + +- Repository: `/home/michele/netgescon/netgescon-day0` +- Focus stabile utente: `0021`, con attenzione anche allo shell tecnico FE `FE221005` (`stabili.id=29`) +- Obiettivo operativo chiuso in questa sessione: + - rendere esplicito e sicuro il CF soggetto nello scarico FE + - semplificare il flusso `ticket-acqua-light` + - rimuovere il footer Filament invasivo su mobile + - riallineare pagina `tabelle-millesimali` a `nord`, `tipo`, `calcolo` + - eliminare i blocchi Blade fragili nelle viste `ticket-acqua` e `ticket-acqua-generale` + +## Verifiche fatte e confermate + +- `php artisan view:clear && php artisan view:cache` eseguito con esito OK dopo gli ultimi fix. +- `php artisan route:list` carica `755` route. +- Il service FE usa il CF dello stabile, non il CF studio dell'amministratore: + - `stabili.id=25 / codice_stabile=0021 / CF=97487690584` + - `stabili.id=29 / codice_stabile=FE221005 / CF=10055221005` +- Il problema operativo dello scarico FE nasceva dal contesto dello stabile attivo in topbar/sessione, non dalla chiamata HTTP finale. +- Nella pagina FE è stato aggiunto un riepilogo esplicito del `Codice fiscale soggetto usato per lo scarico`. +- Le due Blade acqua sono state semplificate spostando il rendering metadati foto in partial condivisa, per evitare parse error residui in staging dovuti a blocchi Blade annidati. + +## File toccati in questa fase + +- `app/Providers/Filament/AdminFilamentPanelProvider.php` + - chain Filament riparata + - footer hook rimosso dal panel +- `app/Filament/Pages/Condomini/TabelleMillesimaliArchivio.php` + - preferenza a `tabelle_millesimali.nord` per ordinamento archivio + - `nord` portato nel payload usato dalla Blade + - lista tabelle ordinata per `nord`, poi `tipo`, poi codice +- `resources/views/filament/pages/condomini/tabelle-millesimali.blade.php` + - badge visivo `Ord. {nord}` + - `tipo` e `calcolo` mantenuti visibili nelle liste `prospetto` e `voci` +- `resources/views/filament/pages/supporto/ticket-acqua.blade.php` +- `resources/views/filament/pages/supporto/ticket-acqua-generale.blade.php` + - blocchi metadati foto sostituiti con partial condivisa +- `resources/views/filament/pages/supporto/partials/photo-metadata.blade.php` + - nuova partial minima in PHP/HTML, senza direttive Blade annidate + +## Comandi rapidi per ripartenza domani + +```bash +cd /home/michele/netgescon/netgescon-day0 +git status --short +php artisan view:clear +php artisan view:cache +php artisan route:list | tail -n 2 +php artisan netgescon:qa-millesimi-spese --stabile=0021 --show-missing=20 +tail -n 120 storage/logs/laravel.log +``` + +## Punti ancora aperti da riprendere + +1. QA millesimi/voci da rendere piu accurato per le gestioni straordinarie legate all'anno/esercizio. +2. Validazione staging reale dopo `git push` + update staging: + - `/admin-filament/condomini/tabelle-millesimali` + - `/admin-filament/supporto/ticket-acqua` + - `/admin-filament/supporto/ticket-acqua-generale` +3. Controllo del bug `fornitore Livewire root` ancora aperto nel tracker. +4. Diagnosi separata dei nominativi rumorosi per `0023`. + +## Prompt consigliato per un altro agent + +"Riparti da `docs/ai/SESSION_HANDOFF.md`. Prima verifica `git status`, poi esegui `php artisan view:clear && php artisan view:cache`. Controlla staging su `tabelle-millesimali`, `ticket-acqua` e `ticket-acqua-generale`. Se il deploy e allineato, passa al raffinamento del QA millesimi/voci per gestioni straordinarie con anno/esercizio, senza fare bonifiche contabili distruttive." + +--- + # SESSION HANDOFF - 2026-04-08 ## Contesto operativo attuale diff --git a/resources/views/filament/pages/condomini/tabelle-millesimali.blade.php b/resources/views/filament/pages/condomini/tabelle-millesimali.blade.php index e271a4c..6c930ce 100644 --- a/resources/views/filament/pages/condomini/tabelle-millesimali.blade.php +++ b/resources/views/filament/pages/condomini/tabelle-millesimali.blade.php @@ -70,8 +70,13 @@ class="block rounded-xl border p-3 transition >
-
- {{ $t['codice'] }} +
+
+ {{ $t['codice'] }} +
+ @if(isset($t['nord']) && $t['nord'] !== null) + Ord. {{ $t['nord'] }} + @endif
{{ $t['nome'] }}
@if(!empty($t['tipo']) || !empty($t['calcolo'])) @@ -241,8 +246,13 @@ class="block rounded-xl border p-3 transition >
-
- {{ $t['codice'] }} +
+
+ {{ $t['codice'] }} +
+ @if(isset($t['nord']) && $t['nord'] !== null) + Ord. {{ $t['nord'] }} + @endif
{{ $t['nome'] }}
@if(!empty($t['tipo']) || !empty($t['calcolo'])) diff --git a/resources/views/filament/pages/supporto/partials/photo-metadata.blade.php b/resources/views/filament/pages/supporto/partials/photo-metadata.blade.php new file mode 100644 index 0000000..ba3ea17 --- /dev/null +++ b/resources/views/filament/pages/supporto/partials/photo-metadata.blade.php @@ -0,0 +1,20 @@ + + + +
+ + + +
+ + + +
+ +
:
+ +
+ \ No newline at end of file diff --git a/resources/views/filament/pages/supporto/ticket-acqua-generale.blade.php b/resources/views/filament/pages/supporto/ticket-acqua-generale.blade.php index cef499e..60e4730 100644 --- a/resources/views/filament/pages/supporto/ticket-acqua-generale.blade.php +++ b/resources/views/filament/pages/supporto/ticket-acqua-generale.blade.php @@ -63,7 +63,9 @@
- @php($service = $this->selectedServiceSnapshot) + @php + $service = $this->selectedServiceSnapshot; + @endphp @if($service)
Riferimenti contratto selezionato
@@ -332,13 +334,7 @@ ]; } @endphp - @if($detailRows !== []) -
- @foreach($detailRows as $detail) -
{{ $detail['label'] }}: {{ $detail['value'] }}
- @endforeach -
- @endif + @include('filament.pages.supporto.partials.photo-metadata', ['badgeRows' => [], 'detailRows' => $detailRows])