hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']) && Schema::hasTable('stabile_servizio_letture'); } public function mount(): void { $reqServizio = request()->integer('servizio'); $this->servizioFilter = $reqServizio > 0 ? $reqServizio : null; $this->mountInteractsWithTable(); } protected function getTableQuery(): Builder { $user = Auth::user(); if (! $user instanceof User) { return StabileServizioLettura::query()->whereRaw('1 = 0'); } $stabileId = StabileContext::resolveActiveStabileId($user); if (! $stabileId) { return StabileServizioLettura::query()->whereRaw('1 = 0'); } return StabileServizioLettura::query() ->where('stabile_id', (int) $stabileId) ->when($this->servizioFilter, fn(Builder $q) => $q->where('stabile_servizio_id', (int) $this->servizioFilter)) ->with([ 'servizio:id,stabile_id,tipo,nome,contatore_matricola', 'fornitore:id,ragione_sociale', 'voceSpesa:id,descrizione,tipo_gestione', 'unitaImmobiliare:id,codice_unita,denominazione,interno,scala,piano', 'fatturaElettronica:id,numero_fattura,data_fattura,totale', ]) ->orderByDesc('periodo_al') ->orderByDesc('id'); } public function table(Table $table): Table { $gestioneOptions = [ 'ordinaria' => 'Ordinaria', 'riscaldamento' => 'Riscaldamento', 'straordinaria' => 'Straordinaria', ]; $tipologiaOptions = [ 'stimata' => 'Stimata', 'effettiva' => 'Effettiva', 'manuale' => 'Manuale', 'automatica' => 'Automatica', 'rettifica' => 'Rettifica', ]; return $table ->striped() ->filters([ SelectFilter::make('servizio_tipo') ->label('Tipo servizio') ->options([ 'acqua' => 'Acqua', 'energia' => 'Energia', 'gas' => 'Gas', 'riscaldamento' => 'Riscaldamento', 'ascensore' => 'Ascensore', 'pulizie' => 'Pulizie', 'assicurazione' => 'Assicurazione', 'privacy' => 'Privacy', 'antenna' => 'Antenna', 'altro' => 'Altro', ]) ->query(function (Builder $query, array $data): Builder { $value = (string) ($data['value'] ?? ''); if ($value === '') { return $query; } return $query->whereHas('servizio', fn(Builder $q) => $q->where('tipo', $value)); }), SelectFilter::make('tipo_gestione') ->label('Gestione (O/R/S)') ->options($gestioneOptions) ->query(function (Builder $query, array $data): Builder { $value = (string) ($data['value'] ?? ''); if ($value === '') { return $query; } return $query->whereHas('voceSpesa', fn(Builder $q) => $q->where('tipo_gestione', $value)); }), ]) ->columns([ TextColumn::make('periodo_dal')->label('Dal')->date('d/m/Y')->sortable()->toggleable(), TextColumn::make('periodo_al')->label('Al')->date('d/m/Y')->sortable(), TextColumn::make('servizio.nome') ->label('Servizio') ->formatStateUsing(function ($state, StabileServizioLettura $record): string { $nome = trim((string) ($record->servizio?->nome ?? '')); if ($nome !== '') { return $nome; } $tipo = trim((string) ($record->servizio?->tipo ?? '')); return $tipo !== '' ? strtoupper($tipo) : '—'; }) ->wrap() ->toggleable(), TextColumn::make('servizio.contatore_matricola')->label('Matricola')->toggleable(isToggledHiddenByDefault: true), TextColumn::make('unitaImmobiliare.denominazione') ->label('Unità immobiliare') ->formatStateUsing(function ($state, StabileServizioLettura $record): string { $ui = $record->unitaImmobiliare; if (! $ui) { return '—'; } $cod = trim((string) ($ui->codice_unita ?? '')); $den = trim((string) ($ui->denominazione ?? '')); if ($cod !== '' && $den !== '') { return $cod . ' - ' . $den; } return $cod !== '' ? $cod : ($den !== '' ? $den : ('UI #' . $ui->id)); }) ->wrap() ->toggleable(), TextColumn::make('consumo_valore') ->label('Consumo') ->formatStateUsing(function ($state, StabileServizioLettura $record): string { $val = $record->consumo_valore; if ($val === null) { return '—'; } $unit = trim((string) ($record->consumo_unita ?? '')); return trim((string) $val) . ($unit !== '' ? (' ' . $unit) : ''); }) ->sortable(), TextColumn::make('importo_totale')->label('Importo')->money('EUR')->sortable()->toggleable(), TextColumn::make('tipologia_lettura') ->label('Tipo lettura') ->formatStateUsing(fn($state) => $tipologiaOptions[strtolower(trim((string) $state))] ?? (string) ($state ?? '—')) ->toggleable(isToggledHiddenByDefault: true), TextColumn::make('canale_acquisizione') ->label('Canale') ->formatStateUsing(function ($state): string { $v = strtolower(trim((string) $state)); return match ($v) { 'manuale' => 'Manuale', 'email' => 'Email', 'whatsapp' => 'WhatsApp', 'import_file' => 'Import file', 'pdf_ocr' => 'PDF/OCR', 'm_bus', 'mbus' => 'Contatore elettronico', default => $v !== '' ? strtoupper($v) : '—', }; }) ->toggleable(), TextColumn::make('riferimento_acquisizione')->label('Riferimento')->toggleable(isToggledHiddenByDefault: true), TextColumn::make('fatturaElettronica.numero_fattura') ->label('Fattura FE') ->url(fn(StabileServizioLettura $record): ?string => $record->fattura_elettronica_id ? FatturaElettronicaScheda::getUrl(['id' => (int) $record->fattura_elettronica_id], panel : 'admin-filament') : null) ->openUrlInNewTab() ->toggleable(), TextColumn::make('voceSpesa.descrizione')->label('Voce spesa')->wrap()->toggleable(isToggledHiddenByDefault: true), TextColumn::make('voceSpesa.tipo_gestione') ->label('Gestione') ->formatStateUsing(fn($state) => $gestioneOptions[strtolower(trim((string) $state))] ?? (string) ($state ?? '—')) ->toggleable(isToggledHiddenByDefault: true), TextColumn::make('fornitore.ragione_sociale')->label('Fornitore')->wrap()->toggleable(isToggledHiddenByDefault: true), TextColumn::make('created_at')->label('Creato')->dateTime('d/m/Y H:i')->toggleable(isToggledHiddenByDefault: true), ]) ->headerActions([ Action::make('create') ->label('Nuova') ->icon('heroicon-o-plus') ->form([ Select::make('stabile_servizio_id') ->label('Servizio') ->options(fn() => $this->getServiziOptions()) ->searchable() ->required(), Select::make('voce_spesa_id') ->label('Voce spesa') ->options(fn() => $this->getVociSpesaOptions()) ->searchable(), Select::make('fornitore_id') ->label('Fornitore') ->options(fn() => $this->getFornitoriOptions()) ->searchable(), Select::make('unita_immobiliare_id') ->label('Unità immobiliare') ->options(fn() => $this->getUnitaOptions()) ->searchable(), DatePicker::make('periodo_dal')->label('Periodo dal'), DatePicker::make('periodo_al')->label('Periodo al'), Select::make('tipologia_lettura') ->label('Tipologia lettura') ->options($tipologiaOptions), Select::make('canale_acquisizione') ->label('Canale acquisizione') ->options([ 'manuale' => 'Manuale', 'email' => 'Email', 'whatsapp' => 'WhatsApp', 'import_file' => 'Import file', 'm_bus' => 'Contatore elettronico', 'pdf_ocr' => 'PDF/OCR', ]), TextInput::make('riferimento_acquisizione')->label('Riferimento acquisizione')->maxLength(191), TextInput::make('lettura_inizio')->label('Lettura inizio')->numeric(), TextInput::make('lettura_fine')->label('Lettura fine')->numeric(), TextInput::make('consumo_valore')->label('Consumo valore')->numeric(), TextInput::make('consumo_unita')->label('Unità')->maxLength(16), TextInput::make('importo_totale')->label('Importo totale')->numeric(), ]) ->action(function (array $data): void { $user = Auth::user(); if (! $user instanceof User) { return; } $stabileId = StabileContext::resolveActiveStabileId($user); if (! $stabileId) { return; } StabileServizioLettura::query()->create([ 'stabile_id' => (int) $stabileId, 'stabile_servizio_id' => (int) ($data['stabile_servizio_id'] ?? 0), 'fornitore_id' => (int) ($data['fornitore_id'] ?? 0) ?: null, 'voce_spesa_id' => (int) ($data['voce_spesa_id'] ?? 0) ?: null, 'unita_immobiliare_id' => (int) ($data['unita_immobiliare_id'] ?? 0) ?: null, 'periodo_dal' => $data['periodo_dal'] ?? null, 'periodo_al' => $data['periodo_al'] ?? null, 'tipologia_lettura' => $data['tipologia_lettura'] ?? null, 'canale_acquisizione' => trim((string) ($data['canale_acquisizione'] ?? '')) ?: 'manuale', 'riferimento_acquisizione' => trim((string) ($data['riferimento_acquisizione'] ?? '')) ?: null, 'lettura_inizio' => $data['lettura_inizio'] ?? null, 'lettura_fine' => $data['lettura_fine'] ?? null, 'consumo_valore' => $data['consumo_valore'] ?? null, 'consumo_unita' => (string) ($data['consumo_unita'] ?? ''), 'importo_totale' => $data['importo_totale'] ?? null, 'created_by' => (int) $user->id, ]); }), ]) ->actions([ Action::make('edit') ->label('Modifica') ->icon('heroicon-o-pencil-square') ->form([ Select::make('stabile_servizio_id') ->label('Servizio') ->options(fn() => $this->getServiziOptions()) ->searchable() ->required(), Select::make('voce_spesa_id') ->label('Voce spesa') ->options(fn() => $this->getVociSpesaOptions()) ->searchable(), Select::make('fornitore_id') ->label('Fornitore') ->options(fn() => $this->getFornitoriOptions()) ->searchable(), Select::make('unita_immobiliare_id') ->label('Unità immobiliare') ->options(fn() => $this->getUnitaOptions()) ->searchable(), DatePicker::make('periodo_dal')->label('Periodo dal'), DatePicker::make('periodo_al')->label('Periodo al'), Select::make('tipologia_lettura') ->label('Tipologia lettura') ->options($tipologiaOptions), Select::make('canale_acquisizione') ->label('Canale acquisizione') ->options([ 'manuale' => 'Manuale', 'email' => 'Email', 'whatsapp' => 'WhatsApp', 'import_file' => 'Import file', 'm_bus' => 'Contatore elettronico', 'pdf_ocr' => 'PDF/OCR', ]), TextInput::make('riferimento_acquisizione')->label('Riferimento acquisizione')->maxLength(191), TextInput::make('lettura_inizio')->label('Lettura inizio')->numeric(), TextInput::make('lettura_fine')->label('Lettura fine')->numeric(), TextInput::make('consumo_valore')->label('Consumo valore')->numeric(), TextInput::make('consumo_unita')->label('Unità')->maxLength(16), TextInput::make('importo_totale')->label('Importo totale')->numeric(), ]) ->fillForm(fn(StabileServizioLettura $record): array=> [ 'stabile_servizio_id' => $record->stabile_servizio_id, 'voce_spesa_id' => $record->voce_spesa_id, 'fornitore_id' => $record->fornitore_id, 'unita_immobiliare_id' => $record->unita_immobiliare_id, 'periodo_dal' => $record->periodo_dal, 'periodo_al' => $record->periodo_al, 'tipologia_lettura' => (string) ($record->tipologia_lettura ?? ''), 'canale_acquisizione' => (string) ($record->canale_acquisizione ?? ''), 'riferimento_acquisizione' => (string) ($record->riferimento_acquisizione ?? ''), 'lettura_inizio' => $record->lettura_inizio, 'lettura_fine' => $record->lettura_fine, 'consumo_valore' => $record->consumo_valore, 'consumo_unita' => (string) ($record->consumo_unita ?? ''), 'importo_totale' => $record->importo_totale, ]) ->action(function (StabileServizioLettura $record, array $data): void { $record->fill([ 'stabile_servizio_id' => (int) ($data['stabile_servizio_id'] ?? 0), 'fornitore_id' => (int) ($data['fornitore_id'] ?? 0) ?: null, 'voce_spesa_id' => (int) ($data['voce_spesa_id'] ?? 0) ?: null, 'unita_immobiliare_id' => (int) ($data['unita_immobiliare_id'] ?? 0) ?: null, 'periodo_dal' => $data['periodo_dal'] ?? null, 'periodo_al' => $data['periodo_al'] ?? null, 'tipologia_lettura' => $data['tipologia_lettura'] ?? null, 'canale_acquisizione' => trim((string) ($data['canale_acquisizione'] ?? '')) ?: null, 'riferimento_acquisizione' => trim((string) ($data['riferimento_acquisizione'] ?? '')) ?: null, 'lettura_inizio' => $data['lettura_inizio'] ?? null, 'lettura_fine' => $data['lettura_fine'] ?? null, 'consumo_valore' => $data['consumo_valore'] ?? null, 'consumo_unita' => (string) ($data['consumo_unita'] ?? ''), 'importo_totale' => $data['importo_totale'] ?? null, ]); $record->save(); }), Action::make('delete') ->label('Elimina') ->icon('heroicon-o-trash') ->color('danger') ->requiresConfirmation() ->action(fn(StabileServizioLettura $record) => $record->delete()), ]); } /** * @return array */ private function getServiziOptions(): array { $user = Auth::user(); if (! $user instanceof User) { return []; } $stabileId = StabileContext::resolveActiveStabileId($user); if (! $stabileId) { return []; } return StabileServizio::query() ->where('stabile_id', (int) $stabileId) ->orderBy('tipo') ->orderBy('nome') ->get(['id', 'tipo', 'nome', 'contatore_matricola']) ->mapWithKeys(function (StabileServizio $s): array { $tipo = strtoupper(trim((string) ($s->tipo ?? ''))); $nome = trim((string) ($s->nome ?? '')); $matr = trim((string) ($s->contatore_matricola ?? '')); $label = $nome !== '' ? $nome : ($tipo !== '' ? $tipo : ('Servizio #' . $s->id)); if ($matr !== '') { $label .= ' (' . $matr . ')'; } return [(int) $s->id => $label]; }) ->all(); } /** * @return array */ private function getFornitoriOptions(): array { $user = Auth::user(); if (! $user instanceof User) { return []; } $query = Fornitore::query(); if (! $user->hasAnyRole(['super-admin', 'admin'])) { $activeStabile = StabileContext::getActiveStabile($user); $adminId = (int) ($activeStabile?->amministratore_id ?: 0); if ($adminId > 0) { $query->where('amministratore_id', $adminId); } } return $query ->orderBy('ragione_sociale') ->get(['id', 'ragione_sociale']) ->mapWithKeys(fn(Fornitore $f) => [(int) $f->id => (string) ($f->ragione_sociale ?? ('Fornitore #' . $f->id))]) ->all(); } /** * @return array */ private function getVociSpesaOptions(): array { $user = Auth::user(); if (! $user instanceof User) { return []; } $stabileId = StabileContext::resolveActiveStabileId($user); if (! $stabileId) { return []; } return VoceSpesa::query() ->where('stabile_id', (int) $stabileId) ->orderBy('tipo_gestione') ->orderBy('descrizione') ->get(['id', 'descrizione', 'tipo_gestione']) ->mapWithKeys(function (VoceSpesa $v): array { $tipo = strtolower(trim((string) ($v->tipo_gestione ?? ''))); $prefix = $tipo !== '' ? strtoupper(substr($tipo, 0, 1)) . ' - ' : ''; return [(int) $v->id => $prefix . (string) ($v->descrizione ?? ('Voce #' . $v->id))]; }) ->all(); } /** * @return array */ private function getUnitaOptions(): array { $user = Auth::user(); if (! $user instanceof User) { return []; } $stabileId = StabileContext::resolveActiveStabileId($user); if (! $stabileId) { return []; } return UnitaImmobiliare::query() ->where('stabile_id', (int) $stabileId) ->orderBy('codice_unita') ->orderBy('interno') ->orderBy('id') ->get(['id', 'codice_unita', 'denominazione', 'interno']) ->mapWithKeys(function (UnitaImmobiliare $u): array { $cod = trim((string) ($u->codice_unita ?? '')); $den = trim((string) ($u->denominazione ?? '')); $int = trim((string) ($u->interno ?? '')); $label = $cod !== '' ? $cod : ('UI #' . $u->id); if ($den !== '') { $label .= ' - ' . $den; } if ($int !== '') { $label .= ' (Int. ' . $int . ')'; } return [(int) $u->id => $label]; }) ->all(); } }