diff --git a/app/Filament/Pages/Condomini/NominativiStabile.php b/app/Filament/Pages/Condomini/NominativiStabile.php index d71ada1..a866e8a 100644 --- a/app/Filament/Pages/Condomini/NominativiStabile.php +++ b/app/Filament/Pages/Condomini/NominativiStabile.php @@ -299,7 +299,20 @@ public function mount(): void { $user = Auth::user(); if ($user instanceof User) { + $requestedStabileId = request()->integer('stabile_id'); + if ($requestedStabileId > 0) { + StabileContext::setActiveStabileId($user, $requestedStabileId); + } + $this->stabileId = StabileContext::resolveActiveStabileId($user); + + if (! $this->stabileId) { + $fallbackStabileId = StabileContext::accessibleStabili($user)->first()?->id; + if ($fallbackStabileId) { + StabileContext::setActiveStabileId($user, (int) $fallbackStabileId); + $this->stabileId = (int) $fallbackStabileId; + } + } } $this->mountInteractsWithTable(); @@ -355,7 +368,7 @@ protected function getTableQuery(): Builder return LegacyCondominNominativo::query()->whereRaw('1 = 0'); } - if (! $this->hasLegacyNominativiForStabile($codStabile) || $this->hasLegacyDuplicateUnits($codStabile)) { + if (! $this->hasLegacyNominativiForStabile($codStabile)) { return $this->buildDomainFallbackQuery((int) $activeStabileId); } @@ -398,20 +411,6 @@ protected function hasLegacyNominativiForStabile(string $codStabile): bool ->exists(); } - protected function hasLegacyDuplicateUnits(string $codStabile): bool - { - return DB::connection('gescon_import') - ->table('condomin') - ->where('cod_stabile', $codStabile) - ->whereNotNull('interno') - ->where('interno', '<>', '') - ->select('scala', 'interno') - ->groupBy('scala', 'interno') - ->havingRaw('COUNT(*) > 1') - ->limit(1) - ->exists(); - } - protected function buildDomainFallbackQuery(int $stabileId): Builder { $today = now()->toDateString(); diff --git a/app/Filament/Pages/Condomini/ServiziStabileArchivio.php b/app/Filament/Pages/Condomini/ServiziStabileArchivio.php index 7a25b62..48d20f8 100644 --- a/app/Filament/Pages/Condomini/ServiziStabileArchivio.php +++ b/app/Filament/Pages/Condomini/ServiziStabileArchivio.php @@ -6,6 +6,7 @@ use App\Models\StabileServizio; use App\Models\StabileServizioLettura; use App\Models\StabileServizioTariffa; +use App\Models\UnitaImmobiliare; use App\Models\User; use App\Models\VoceSpesa; use App\Support\AnnoGestioneContext; @@ -27,6 +28,7 @@ use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\URL; use UnitEnum; class ServiziStabileArchivio extends Page implements HasTable @@ -69,6 +71,121 @@ public function setAcquaTab(string $tab): void $this->acquaTab = in_array($tab, $allowed, true) ? $tab : 'dashboard'; } + public function prepareAcquaReadingCampaign(): void + { + $stabileId = $this->resolveActiveStabileId(); + $servizio = $this->resolveActiveAcquaServizio(); + + if (! $stabileId || ! $servizio) { + Notification::make()->title('Servizio acqua attivo non disponibile per lo stabile selezionato.')->warning()->send(); + return; + } + + $units = UnitaImmobiliare::query() + ->where('stabile_id', $stabileId) + ->whereNull('deleted_at') + ->orderBy('scala') + ->orderBy('interno') + ->orderBy('id') + ->get(['id', 'codice_unita', 'scala', 'interno']); + + if ($units->isEmpty()) { + Notification::make()->title('Nessuna unità immobiliare disponibile per avviare la campagna letture.')->warning()->send(); + return; + } + + $year = $this->resolveActiveAnnoGestione(); + $created = 0; + $updated = 0; + + foreach ($units as $unit) { + $completed = StabileServizioLettura::query() + ->where('stabile_id', $stabileId) + ->where('stabile_servizio_id', (int) $servizio->id) + ->where('unita_immobiliare_id', (int) $unit->id) + ->whereYear('created_at', $year) + ->whereNotNull('lettura_fine') + ->exists(); + + if ($completed) { + continue; + } + + $previous = StabileServizioLettura::query() + ->where('stabile_id', $stabileId) + ->where('stabile_servizio_id', (int) $servizio->id) + ->where('unita_immobiliare_id', (int) $unit->id) + ->whereNotNull('lettura_fine') + ->orderByDesc('periodo_al') + ->orderByDesc('id') + ->first(); + + $requestRow = StabileServizioLettura::query() + ->where('stabile_id', $stabileId) + ->where('stabile_servizio_id', (int) $servizio->id) + ->where('unita_immobiliare_id', (int) $unit->id) + ->whereYear('created_at', $year) + ->whereNull('lettura_fine') + ->orderByDesc('id') + ->first(); + + $requestReference = 'PUBREQ:' . (int) $servizio->id . ':' . (int) $unit->id . ':' . $year; + $requestPayload = [ + 'stabile_id' => $stabileId, + 'stabile_servizio_id' => (int) $servizio->id, + 'unita_immobiliare_id' => (int) $unit->id, + 'fornitore_id' => $servizio->fornitore_id, + 'periodo_dal' => $previous?->periodo_al, + 'periodo_al' => null, + 'tipologia_lettura' => 'richiesta_autolettura', + 'canale_acquisizione' => 'portale_pubblico', + 'riferimento_acquisizione' => $requestReference, + 'workflow_stato' => 'richiesta_inviata', + 'richiesta_lettura_inviata_at' => now(), + 'deadline_lettura_at' => now()->addDays(7), + 'lettura_precedente_valore' => $previous?->lettura_fine, + 'lettura_inizio' => $previous?->lettura_fine, + 'raw' => [ + 'source' => 'campagna_letture_acqua', + 'year' => $year, + 'unit_label' => trim((string) ($unit->codice_unita ?? '') . ' ' . (string) ($unit->interno ?? '')), + ], + ]; + + if ($requestRow) { + $requestRow->fill($requestPayload); + $requestRow->save(); + $updated++; + continue; + } + + StabileServizioLettura::query()->create($requestPayload); + $created++; + } + + Notification::make() + ->title('Campagna letture acqua preparata') + ->body("Richieste create: {$created} · richieste aggiornate: {$updated}") + ->success() + ->send(); + } + + public function markAcquaReadingReminder(int $readingId): void + { + $reading = StabileServizioLettura::query()->find($readingId); + if (! $reading) { + return; + } + + $reading->fill([ + 'sollecito_inviato_at' => now(), + 'workflow_stato' => 'sollecito_inviato', + ]); + $reading->save(); + + Notification::make()->title('Sollecito registrato')->success()->send(); + } + public function ensureAcquaAceaContract(): void { $stabileId = $this->resolveActiveStabileId(); @@ -478,6 +595,34 @@ private function resolveActiveAnnoGestione(): int return AnnoGestioneContext::resolveActiveAnno($user instanceof User ? $user : null); } + private function resolveActiveAcquaServizio(): ?StabileServizio + { + $stabileId = $this->resolveActiveStabileId(); + if (! $stabileId) { + return null; + } + + return StabileServizio::query() + ->where('stabile_id', $stabileId) + ->where('tipo', 'acqua') + ->orderByDesc('attivo') + ->orderBy('id') + ->first(); + } + + private function buildPublicAcquaReadingUrl(int $servizioId, int $unitaId, ?int $requestId = null): string + { + return URL::temporarySignedRoute( + 'public.water-reading.show', + now()->addDays(30), + array_filter([ + 'servizio' => $servizioId, + 'unita' => $unitaId, + 'request' => $requestId, + ], fn ($value) => $value !== null) + ); + } + /** @return array */ private function resolveLegacyCodiciStabile(): array { @@ -1201,6 +1346,107 @@ public function getAcquaLettureCondominiProperty(): array ->all(); } + /** @return array{totale:int,completate:int,pendenti:int,sollecitate:int} */ + public function getAcquaCampagnaStatsProperty(): array + { + $rows = $this->acquaCampagnaRows; + + return [ + 'totale' => count($rows), + 'completate' => count(array_filter($rows, fn (array $row): bool => $row['status'] === 'fatta')), + 'pendenti' => count(array_filter($rows, fn (array $row): bool => in_array($row['status'], ['richiesta', 'non_richiesta'], true))), + 'sollecitate' => count(array_filter($rows, fn (array $row): bool => $row['status'] === 'sollecito')), + ]; + } + + /** @return array> */ + public function getAcquaCampagnaRowsProperty(): array + { + $stabileId = $this->resolveActiveStabileId(); + $servizio = $this->resolveActiveAcquaServizio(); + if (! $stabileId || ! $servizio) { + return []; + } + + $year = $this->resolveActiveAnnoGestione(); + + $units = UnitaImmobiliare::query() + ->where('stabile_id', $stabileId) + ->whereNull('deleted_at') + ->orderBy('scala') + ->orderBy('interno') + ->orderBy('id') + ->get(['id', 'codice_unita', 'denominazione', 'scala', 'interno']); + + $nominativi = DB::table('unita_immobiliare_nominativi') + ->whereIn('unita_immobiliare_id', $units->pluck('id')->all()) + ->orderByDesc('updated_at') + ->orderByDesc('id') + ->get(['unita_immobiliare_id', 'nominativo']); + + $nominativiByUnit = []; + foreach ($nominativi as $row) { + $unitId = (int) ($row->unita_immobiliare_id ?? 0); + if ($unitId > 0 && ! isset($nominativiByUnit[$unitId])) { + $nominativiByUnit[$unitId] = trim((string) ($row->nominativo ?? '')); + } + } + + $readingRows = StabileServizioLettura::query() + ->where('stabile_id', $stabileId) + ->where('stabile_servizio_id', (int) $servizio->id) + ->whereIn('unita_immobiliare_id', $units->pluck('id')->all()) + ->orderByDesc('created_at') + ->orderByDesc('id') + ->get(); + + $currentYearByUnit = []; + $latestRealByUnit = []; + foreach ($readingRows as $row) { + $unitId = (int) ($row->unita_immobiliare_id ?? 0); + if ($unitId <= 0) { + continue; + } + + $rowYear = optional($row->created_at)->year ?: optional($row->periodo_al)->year; + if ((int) $rowYear === $year && ! isset($currentYearByUnit[$unitId])) { + $currentYearByUnit[$unitId] = $row; + } + + if ($row->lettura_fine !== null && ! isset($latestRealByUnit[$unitId])) { + $latestRealByUnit[$unitId] = $row; + } + } + + return $units->map(function (UnitaImmobiliare $unit) use ($currentYearByUnit, $latestRealByUnit, $nominativiByUnit, $servizio): array { + $current = $currentYearByUnit[(int) $unit->id] ?? null; + $latestReal = $latestRealByUnit[(int) $unit->id] ?? null; + + $status = 'non_richiesta'; + if ($current && $current->lettura_fine !== null) { + $status = 'fatta'; + } elseif ($current && $current->sollecito_inviato_at) { + $status = 'sollecito'; + } elseif ($current && $current->richiesta_lettura_inviata_at) { + $status = 'richiesta'; + } + + return [ + 'unit_id' => (int) $unit->id, + 'unit_label' => trim((string) ($unit->codice_unita ?? '') . ' ' . (string) ($unit->interno ?? '')) ?: ('UI #' . (int) $unit->id), + 'nominativo' => $nominativiByUnit[(int) $unit->id] ?? (trim((string) ($unit->denominazione ?? '')) ?: 'Nominativo da completare'), + 'previous_reading' => $latestReal?->lettura_fine, + 'request_id' => $current?->id, + 'status' => $status, + 'requested_at' => optional($current?->richiesta_lettura_inviata_at)->format('d/m/Y H:i'), + 'deadline_at' => optional($current?->deadline_lettura_at)->format('d/m/Y'), + 'completed_at' => optional($current?->created_at)->format('d/m/Y H:i'), + 'latest_value' => $current?->lettura_fine, + 'public_url' => $this->buildPublicAcquaReadingUrl((int) $servizio->id, (int) $unit->id, $current?->id ? (int) $current->id : null), + ]; + })->all(); + } + /** @return array> */ public function getAcquaTariffeRowsProperty(): array { diff --git a/app/Http/Controllers/PublicAccess/WaterReadingRequestController.php b/app/Http/Controllers/PublicAccess/WaterReadingRequestController.php new file mode 100644 index 0000000..3fa16f2 --- /dev/null +++ b/app/Http/Controllers/PublicAccess/WaterReadingRequestController.php @@ -0,0 +1,168 @@ +integer('servizio'); + $unitaId = (int) $request->integer('unita'); + $requestId = (int) $request->integer('request'); + + $servizio = StabileServizio::query() + ->where('id', $servizioId) + ->where('tipo', 'acqua') + ->firstOrFail(); + + $unita = UnitaImmobiliare::query() + ->with('stabile:id,denominazione,codice_stabile') + ->where('id', $unitaId) + ->where('stabile_id', (int) $servizio->stabile_id) + ->firstOrFail(); + + $pendingRequest = $requestId > 0 + ? StabileServizioLettura::query() + ->where('id', $requestId) + ->where('stabile_servizio_id', $servizioId) + ->where('unita_immobiliare_id', $unitaId) + ->first() + : null; + + $previous = StabileServizioLettura::query() + ->where('stabile_servizio_id', $servizioId) + ->where('unita_immobiliare_id', $unitaId) + ->whereNotNull('lettura_fine') + ->when($pendingRequest, fn ($query) => $query->where('id', '!=', (int) $pendingRequest->id)) + ->orderByDesc('periodo_al') + ->orderByDesc('id') + ->first(); + + $submitUrl = URL::temporarySignedRoute('public.water-reading.store', now()->addDays(30), array_filter([ + 'servizio' => $servizioId, + 'unita' => $unitaId, + 'request' => $pendingRequest?->id, + ])); + + return view('public.water-reading.show', [ + 'servizio' => $servizio, + 'unita' => $unita, + 'pendingRequest' => $pendingRequest, + 'previous' => $previous, + 'submitUrl' => $submitUrl, + ]); + } + + public function store(Request $request): RedirectResponse + { + $servizioId = (int) $request->integer('servizio'); + $unitaId = (int) $request->integer('unita'); + $requestId = (int) $request->integer('request'); + + $servizio = StabileServizio::query() + ->where('id', $servizioId) + ->where('tipo', 'acqua') + ->firstOrFail(); + + $unita = UnitaImmobiliare::query() + ->where('id', $unitaId) + ->where('stabile_id', (int) $servizio->stabile_id) + ->firstOrFail(); + + $validated = $request->validate([ + 'lettura_attuale' => ['required', 'numeric', 'min:0'], + 'data_lettura' => ['nullable', 'date'], + 'rilevatore_nome' => ['required', 'string', 'max:255'], + 'rilevatore_contatto' => ['nullable', 'string', 'max:255'], + 'note' => ['nullable', 'string', 'max:2000'], + 'foto_1' => ['nullable', 'image', 'max:8192'], + 'foto_2' => ['nullable', 'image', 'max:8192'], + ]); + + $pendingRequest = $requestId > 0 + ? StabileServizioLettura::query() + ->where('id', $requestId) + ->where('stabile_servizio_id', $servizioId) + ->where('unita_immobiliare_id', $unitaId) + ->first() + : null; + + $previous = StabileServizioLettura::query() + ->where('stabile_servizio_id', $servizioId) + ->where('unita_immobiliare_id', $unitaId) + ->whereNotNull('lettura_fine') + ->when($pendingRequest, fn ($query) => $query->where('id', '!=', (int) $pendingRequest->id)) + ->orderByDesc('periodo_al') + ->orderByDesc('id') + ->first(); + + $letturaInizio = $previous?->lettura_fine !== null ? (float) $previous->lettura_fine : null; + $letturaFine = (float) $validated['lettura_attuale']; + $consumo = $letturaInizio !== null ? round($letturaFine - $letturaInizio, 3) : null; + + if ($consumo !== null && $consumo < 0) { + return back()->withErrors([ + 'lettura_attuale' => 'La lettura attuale non puo essere inferiore a quella precedente.', + ])->withInput(); + } + + $photoPaths = []; + foreach (['foto_1', 'foto_2'] as $photoField) { + if ($request->hasFile($photoField)) { + $photoPaths[] = $request->file($photoField)?->store('letture-acqua-public', 'public'); + } + } + + $payload = [ + 'stabile_id' => (int) $servizio->stabile_id, + 'stabile_servizio_id' => (int) $servizio->id, + 'unita_immobiliare_id' => (int) $unita->id, + 'fornitore_id' => $servizio->fornitore_id, + 'periodo_dal' => $previous?->periodo_al, + 'periodo_al' => isset($validated['data_lettura']) ? Carbon::parse((string) $validated['data_lettura'])->toDateString() : now()->toDateString(), + 'tipologia_lettura' => 'autolettura_link_pubblico', + 'canale_acquisizione' => 'portale_pubblico', + 'workflow_stato' => 'ricevuta', + 'riferimento_acquisizione' => $pendingRequest?->riferimento_acquisizione ?: ('PUBREAD:' . (int) $servizio->id . ':' . (int) $unita->id . ':' . now()->format('YmdHis')), + 'rilevatore_tipo' => 'link_pubblico', + 'rilevatore_nome' => trim((string) $validated['rilevatore_nome']), + 'lettura_precedente_valore' => $letturaInizio, + 'lettura_inizio' => $letturaInizio, + 'lettura_fine' => $letturaFine, + 'lettura_foto_path' => $photoPaths[0] ?? null, + 'lettura_foto_metadata' => [ + 'paths' => $photoPaths, + 'contact' => trim((string) ($validated['rilevatore_contatto'] ?? '')), + 'note' => trim((string) ($validated['note'] ?? '')), + ], + 'consumo_valore' => $consumo, + 'consumo_unita' => 'mc', + 'raw' => [ + 'source' => 'public_water_reading_link', + 'contact' => trim((string) ($validated['rilevatore_contatto'] ?? '')), + 'note' => trim((string) ($validated['note'] ?? '')), + 'photo_paths' => $photoPaths, + 'request_id' => $pendingRequest?->id, + ], + ]; + + if ($pendingRequest) { + $pendingRequest->fill($payload); + $pendingRequest->save(); + } else { + StabileServizioLettura::query()->create($payload); + } + + return redirect()->back()->with('success', 'Lettura acqua inviata correttamente.'); + } +} \ No newline at end of file diff --git a/resources/views/filament/pages/condomini/servizi-stabile-archivio.blade.php b/resources/views/filament/pages/condomini/servizi-stabile-archivio.blade.php index 3431b57..16557f0 100644 --- a/resources/views/filament/pages/condomini/servizi-stabile-archivio.blade.php +++ b/resources/views/filament/pages/condomini/servizi-stabile-archivio.blade.php @@ -11,6 +11,8 @@ $legacyOpsRows = $this->acquaLegacyOperazioniRows; $acquaContratto = $this->acquaContrattoStabile; $acquaRipartoNominativi = $this->acquaRipartoNominativiLegacy; + $campagnaStats = $this->acquaCampagnaStats; + $campagnaRows = $this->acquaCampagnaRows; @endphp
@@ -236,6 +238,90 @@ class="pb-3 px-1 border-b-2 font-medium text-sm {{ $acquaTab === 'servizi' ? 'bo @if($acquaTab === 'letture')
+
+
+
+
Campagna letture acqua per unità
+
Primo slice operativo: genera richieste per le unità dello stabile, dividi fatte e non fatte, e usa un link pubblico firmato per inviare lettura attuale più massimo due foto.
+
+ + Prepara / aggiorna campagna letture + +
+ +
+
+
Unità
+
{{ $campagnaStats['totale'] }}
+
+
+
Fatte
+
{{ $campagnaStats['completate'] }}
+
+
+
Pendenti
+
{{ $campagnaStats['pendenti'] }}
+
+
+
Sollecitate
+
{{ $campagnaStats['sollecitate'] }}
+
+
+ +
+ + + + + + + + + + + + + @forelse($campagnaRows as $row) + + + + + + + + + @empty + + + + @endforelse + +
UnitàNominativoLettura precedenteStatoRichiestaAzioni
{{ $row['unit_label'] }}{{ $row['nominativo'] }}{{ $row['previous_reading'] !== null ? number_format((float) $row['previous_reading'], 3, ',', '.') : '—' }} + @if($row['status'] === 'fatta') + Fatta + @elseif($row['status'] === 'sollecito') + Sollecito + @elseif($row['status'] === 'richiesta') + Richiesta inviata + @else + Da inviare + @endif + + {{ $row['requested_at'] ?: '—' }} + @if($row['deadline_at']) +
Scadenza {{ $row['deadline_at'] }}
+ @endif +
+
+ Apri link + @if($row['request_id'] && $row['status'] !== 'fatta') + + @endif +
+
Nessuna unità disponibile per la campagna letture.
+
+
+
Base nominativi riparto ACQUA (legacy) per inserimento letture manuali
diff --git a/resources/views/filament/pages/fornitore/ticket-intervento-scheda.blade.php b/resources/views/filament/pages/fornitore/ticket-intervento-scheda.blade.php index c44b872..91aadf1 100644 --- a/resources/views/filament/pages/fornitore/ticket-intervento-scheda.blade.php +++ b/resources/views/filament/pages/fornitore/ticket-intervento-scheda.blade.php @@ -72,6 +72,7 @@ Lavorazioni Collaboratori Rubrica clienti + Impostazioni Prodotti
@@ -596,51 +597,50 @@
- - - @if($attachmentPreview) -
-
-
-
-
{{ $attachmentPreview['name'] ?? 'Allegato' }}
- @if(!empty($attachmentPreview['description'])) -
{{ $attachmentPreview['description'] }}
- @endif + @if($attachmentPreview) +
+
+
+
+
{{ $attachmentPreview['name'] ?? 'Allegato' }}
+ @if(!empty($attachmentPreview['description'])) +
{{ $attachmentPreview['description'] }}
+ @endif +
+
+ @if($attachmentPreview['is_image'] ?? false) + + + + @elseif($attachmentPreview['is_pdf'] ?? false) + + Pagina + + + @endif + Apri in nuova scheda + +
-
+ +
@if($attachmentPreview['is_image'] ?? false) - - - - @elseif($attachmentPreview['is_pdf'] ?? false) - - Pagina - - - @endif - Apri in nuova scheda - -
-
- -
- @if($attachmentPreview['is_image'] ?? false) -
-
- Anteprima allegato +
+
+ Anteprima allegato +
-
- @elseif($attachmentPreview['is_pdf'] ?? false) - - @else -
- Anteprima non disponibile per questo formato. Scarica o apri il file: - Apri file -
- @endif + @elseif($attachmentPreview['is_pdf'] ?? false) + + @else +
+ Anteprima non disponibile per questo formato. Scarica o apri il file: + Apri file +
+ @endif +
-
- @endif + @endif +
\ No newline at end of file diff --git a/resources/views/filament/pages/gescon/table.blade.php b/resources/views/filament/pages/gescon/table.blade.php index 3693976..a04a7e9 100644 --- a/resources/views/filament/pages/gescon/table.blade.php +++ b/resources/views/filament/pages/gescon/table.blade.php @@ -123,7 +123,7 @@ class="inline-flex h-4 w-4 items-center justify-center rounded-full text-slate-5
Tag: {{ $match->tags }}
@endif @if($match->note) -
{{ \\Illuminate\\Support\\Str::limit((string) $match->note, 120) }}
+
{{ \Illuminate\Support\Str::limit((string) $match->note, 120) }}
@endif @endforeach diff --git a/resources/views/public/water-reading/show.blade.php b/resources/views/public/water-reading/show.blade.php new file mode 100644 index 0000000..c0f1757 --- /dev/null +++ b/resources/views/public/water-reading/show.blade.php @@ -0,0 +1,84 @@ + + + + + + + Lettura acqua - {{ $unita->stabile->denominazione ?? 'NetGescon' }} + @vite(['resources/css/app.css', 'resources/js/app.js']) + + +
+
+

Invio lettura acqua

+

Compila la lettura attuale del contatore per l'unità indicata. Puoi allegare massimo due foto.

+
+ + @if (session('success')) +
{{ session('success') }}
+ @endif + + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + +
+
+
Stabile: {{ $unita->stabile->codice_stabile ?? '' }} - {{ $unita->stabile->denominazione ?? '-' }}
+
Unità: {{ $unita->codice_unita ?: ('UI #' . (int) $unita->id) }}
+
Servizio: {{ $servizio->nome ?: 'Acqua' }}
+
Matricola: {{ $servizio->contatore_matricola ?: '—' }}
+
Lettura precedente: {{ $previous?->lettura_fine !== null ? number_format((float) $previous->lettura_fine, 3, ',', '.') : '—' }}
+
Ultima data nota: {{ optional($previous?->periodo_al)->format('d/m/Y') ?: '—' }}
+
+
+ +
+ @csrf + +
+ + + + +
+ +
+ + +
+ + + + +
+
+ + \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 50ce616..928a04c 100755 --- a/routes/web.php +++ b/routes/web.php @@ -45,6 +45,11 @@ return redirect('/admin-filament'); }); +Route::middleware('signed')->prefix('public/letture-acqua')->name('public.water-reading.')->group(function () { + Route::get('/', [\App\Http\Controllers\PublicAccess\WaterReadingRequestController::class, 'show'])->name('show'); + Route::post('/', [\App\Http\Controllers\PublicAccess\WaterReadingRequestController::class, 'store'])->name('store'); +}); + // --- Authenticated Routes --- Route::middleware(['auth', 'verified'])->group(function () {