Browse Source

Collega route, observer, menu e comando fest:salute.

Senza questo pezzo i nuovi flussi non sono raggiungibili in produzione.

Co-authored-by: Cursor <cursoragent@cursor.com>
marcofalabretti 2 weeks ago
parent
commit
26459ab1e5

+ 311
- 0
app/Console/Commands/FestSalute.php View File

@@ -0,0 +1,311 @@
1
+<?php
2
+
3
+namespace App\Console\Commands;
4
+
5
+use App\Models\Cucina;
6
+use App\Models\Dispositivo;
7
+use App\Models\Endpoint;
8
+use App\Models\PrintJob;
9
+use Illuminate\Console\Command;
10
+use Illuminate\Support\Facades\DB;
11
+use Illuminate\Support\Facades\File;
12
+use Illuminate\Support\Facades\Redis;
13
+use Illuminate\Support\Facades\Schema;
14
+
15
+class FestSalute extends Command
16
+{
17
+    protected $signature = 'fest:salute';
18
+
19
+    protected $description = 'Verifica Redis, code, stampe, endpoint e configurazione cassa/cucina';
20
+
21
+    private int $ko = 0;
22
+
23
+    private int $attenzione = 0;
24
+
25
+    public function handle(): int
26
+    {
27
+        $this->info('Fest — controllo salute');
28
+        $this->newLine();
29
+
30
+        $this->checkDatabase();
31
+        $this->checkMigrazioni();
32
+        $this->checkRedis();
33
+        $this->checkHorizon();
34
+        $this->checkCodaMail();
35
+        $this->checkMailConfig();
36
+        $this->checkEndpoint();
37
+        $this->checkCasse();
38
+        $this->checkCucine();
39
+        $this->checkPrintJobBloccati();
40
+
41
+        $this->newLine();
42
+        if ($this->ko > 0) {
43
+            $this->error("Esito: KO ({$this->ko} errori, {$this->attenzione} avvisi).");
44
+
45
+            return self::FAILURE;
46
+        }
47
+
48
+        if ($this->attenzione > 0) {
49
+            $this->warn("Esito: OK con avvisi ({$this->attenzione}). Il sistema è su, controlla le righe ATTENZIONE.");
50
+
51
+            return self::SUCCESS;
52
+        }
53
+
54
+        $this->info('Esito: OK. Controlli base superati.');
55
+
56
+        return self::SUCCESS;
57
+    }
58
+
59
+    private function checkDatabase(): void
60
+    {
61
+        try {
62
+            DB::connection()->getPdo();
63
+            $this->ok('Database', (string) DB::connection()->getDatabaseName());
64
+        } catch (\Throwable $e) {
65
+            $this->koCheck('Database', $e->getMessage());
66
+        }
67
+    }
68
+
69
+    private function checkMigrazioni(): void
70
+    {
71
+        try {
72
+            if (! Schema::hasTable('migrations')) {
73
+                $this->koCheck('Migrazioni', 'tabella migrations assente');
74
+
75
+                return;
76
+            }
77
+
78
+            $ran = DB::table('migrations')->pluck('migration')->all();
79
+            $files = collect(File::files(database_path('migrations')))
80
+                ->map(fn ($file) => pathinfo($file->getFilename(), PATHINFO_FILENAME));
81
+            $pending = $files->reject(fn (string $name) => in_array($name, $ran, true))->values();
82
+
83
+            if ($pending->isEmpty()) {
84
+                $this->ok('Migrazioni', 'nessuna in sospeso');
85
+
86
+                return;
87
+            }
88
+
89
+            $elenco = $pending->take(5)->implode(', ');
90
+            $extra = $pending->count() > 5 ? '…' : '';
91
+            $this->koCheck('Migrazioni', $pending->count().' in sospeso ('.$elenco.$extra.'). Esegui php artisan migrate');
92
+        } catch (\Throwable $e) {
93
+            $this->koCheck('Migrazioni', $e->getMessage());
94
+        }
95
+    }
96
+
97
+    private function checkRedis(): void
98
+    {
99
+        try {
100
+            Redis::connection()->ping();
101
+            $this->ok('Redis', 'risponde');
102
+        } catch (\Throwable $e) {
103
+            $this->koCheck('Redis', $e->getMessage());
104
+        }
105
+    }
106
+
107
+    private function checkHorizon(): void
108
+    {
109
+        if (! interface_exists(\Laravel\Horizon\Contracts\MasterSupervisorRepository::class)) {
110
+            $this->warnCheck('Horizon', 'pacchetto non disponibile: avvia php artisan queue:work redis');
111
+
112
+            return;
113
+        }
114
+
115
+        try {
116
+            $masters = app(\Laravel\Horizon\Contracts\MasterSupervisorRepository::class)->all();
117
+            $running = collect($masters)->contains(
118
+                fn ($master) => ($master->status ?? null) === 'running'
119
+            );
120
+
121
+            if ($running) {
122
+                $this->ok('Horizon', 'in esecuzione');
123
+
124
+                return;
125
+            }
126
+
127
+            $this->koCheck(
128
+                'Horizon',
129
+                'non in esecuzione. Avvia php artisan horizon (oppure queue:work redis) o stampe e conferma-tutte restano in coda'
130
+            );
131
+        } catch (\Throwable $e) {
132
+            $this->koCheck('Horizon', $e->getMessage());
133
+        }
134
+    }
135
+
136
+    private function checkCodaMail(): void
137
+    {
138
+        $connection = (string) config('queue.default');
139
+        if ($connection === 'redis') {
140
+            $this->ok('Coda mail', 'QUEUE_CONNECTION=redis (Horizon può processare le email)');
141
+
142
+            return;
143
+        }
144
+
145
+        if ($connection === 'sync') {
146
+            $this->koCheck('Coda mail', 'QUEUE_CONNECTION=sync: le mail partono in-process, rischio timeout su conferma tutte');
147
+
148
+            return;
149
+        }
150
+
151
+        $this->warnCheck(
152
+            'Coda mail',
153
+            'QUEUE_CONNECTION='.$connection.'. Horizon ascolta Redis: senza un worker su '.$connection.' le email prenotazioni non partono'
154
+        );
155
+    }
156
+
157
+    private function checkMailConfig(): void
158
+    {
159
+        $from = (string) config('mail.from.address');
160
+        $mailer = (string) config('mail.default');
161
+        if (! filled($from) || $from === 'hello@example.com') {
162
+            $this->warnCheck('Mail', 'mittente non configurato (mail.from.address)');
163
+
164
+            return;
165
+        }
166
+
167
+        $this->ok('Mail', 'mailer='.$mailer.', from='.$from);
168
+    }
169
+
170
+    private function checkEndpoint(): void
171
+    {
172
+        try {
173
+            $attivi = Endpoint::query()->where('status', Endpoint::ATTIVO)->get();
174
+            if ($attivi->isEmpty()) {
175
+                $this->warnCheck('Endpoint', 'nessun FestAgent attivo: le stampe non escono');
176
+
177
+                return;
178
+            }
179
+
180
+            $stale = $attivi->filter(function (Endpoint $endpoint) {
181
+                $hb = $endpoint->last_heartbeat;
182
+                if ($hb === null) {
183
+                    return true;
184
+                }
185
+
186
+                return $hb->lt(now()->subMinutes(5));
187
+            });
188
+
189
+            if ($stale->isNotEmpty()) {
190
+                $nomi = $stale->map(fn (Endpoint $e) => $e->label ?: '#'.$e->id)->take(5)->implode(', ');
191
+                $this->koCheck(
192
+                    'Endpoint',
193
+                    $stale->count().' attivi senza heartbeat recente ('.$nomi.'). Agent spento o rete?'
194
+                );
195
+
196
+                return;
197
+            }
198
+
199
+            $this->ok('Endpoint', $attivi->count().' attivi, heartbeat ok');
200
+        } catch (\Throwable $e) {
201
+            $this->koCheck('Endpoint', $e->getMessage());
202
+        }
203
+    }
204
+
205
+    private function checkCasse(): void
206
+    {
207
+        try {
208
+            $casse = Dispositivo::query()
209
+                ->whereIn('tipo', [Dispositivo::CASSA, Dispositivo::KIOSK, Dispositivo::CAMERIERE])
210
+                ->where('is_attivo', true)
211
+                ->get();
212
+
213
+            if ($casse->isEmpty()) {
214
+                $this->warnCheck('Casse', 'nessun punto vendita attivo');
215
+
216
+                return;
217
+            }
218
+
219
+            $senza = $casse->filter(fn (Dispositivo $d) => $d->stampante_dispositivo() === null);
220
+            if ($senza->isNotEmpty()) {
221
+                $nomi = $senza->map(fn (Dispositivo $d) => $d->nome ?: '#'.$d->id)->take(8)->implode(', ');
222
+                $this->koCheck('Casse', $senza->count().' senza stampante valida: '.$nomi);
223
+
224
+                return;
225
+            }
226
+
227
+            $this->ok('Casse', $casse->count().' attive con stampante');
228
+        } catch (\Throwable $e) {
229
+            $this->koCheck('Casse', $e->getMessage());
230
+        }
231
+    }
232
+
233
+    private function checkCucine(): void
234
+    {
235
+        try {
236
+            $cucine = Cucina::query()->where('is_attiva', true)->get();
237
+            if ($cucine->isEmpty()) {
238
+                $this->warnCheck('Cucine', 'nessuna cucina attiva');
239
+
240
+                return;
241
+            }
242
+
243
+            $senza = $cucine->filter(fn (Cucina $c) => $c->stampante_id === null);
244
+            if ($senza->isNotEmpty()) {
245
+                $nomi = $senza->map(fn (Cucina $c) => $c->nome ?: '#'.$c->id)->take(8)->implode(', ');
246
+                $this->koCheck('Cucine', $senza->count().' attive senza stampante: '.$nomi);
247
+
248
+                return;
249
+            }
250
+
251
+            $this->ok('Cucine', $cucine->count().' attive con stampante');
252
+        } catch (\Throwable $e) {
253
+            $this->koCheck('Cucine', $e->getMessage());
254
+        }
255
+    }
256
+
257
+    private function checkPrintJobBloccati(): void
258
+    {
259
+        try {
260
+            $limite = now()->subMinutes(10);
261
+            $inAttesa = PrintJob::query()
262
+                ->where('stato', PrintJob::STATO_IN_ATTESA)
263
+                ->where('created_at', '<', $limite)
264
+                ->count();
265
+            $inCoda = PrintJob::query()
266
+                ->where('stato', PrintJob::STATO_IN_CODA)
267
+                ->where('created_at', '<', $limite)
268
+                ->count();
269
+            $fallitiOggi = PrintJob::query()
270
+                ->where('stato', PrintJob::STATO_FALLITO)
271
+                ->whereDate('created_at', today())
272
+                ->count();
273
+
274
+            if ($inAttesa > 0 || $inCoda > 0) {
275
+                $this->koCheck(
276
+                    'PrintJob',
277
+                    "{$inAttesa} in_attesa da >10 min (worker Redis?), {$inCoda} in_coda da >10 min (agent?)"
278
+                );
279
+
280
+                return;
281
+            }
282
+
283
+            if ($fallitiOggi > 0) {
284
+                $this->warnCheck('PrintJob', $fallitiOggi.' falliti oggi');
285
+
286
+                return;
287
+            }
288
+
289
+            $this->ok('PrintJob', 'nessun job bloccato');
290
+        } catch (\Throwable $e) {
291
+            $this->koCheck('PrintJob', $e->getMessage());
292
+        }
293
+    }
294
+
295
+    private function ok(string $voce, string $dettaglio): void
296
+    {
297
+        $this->line('<info>[OK]</info> '.$voce.' — '.$dettaglio);
298
+    }
299
+
300
+    private function koCheck(string $voce, string $dettaglio): void
301
+    {
302
+        $this->ko++;
303
+        $this->line('<error>[KO]</error> '.$voce.' — '.$dettaglio);
304
+    }
305
+
306
+    private function warnCheck(string $voce, string $dettaglio): void
307
+    {
308
+        $this->attenzione++;
309
+        $this->line('<comment>[ATTENZIONE]</comment> '.$voce.' — '.$dettaglio);
310
+    }
311
+}

+ 11
- 1
app/Providers/AppServiceProvider.php View File

@@ -5,11 +5,17 @@ namespace App\Providers;
5 5
 use App\Models\Ordine;
6 6
 use App\Observers\OrdineObserver;
7 7
 use App\Observers\DispositivoObserver;
8
+use App\Models\Dispositivo;
8 9
 use App\Observers\PagamentoObserver;
9 10
 use App\Models\Pagamento;
10
-use App\Models\Dispositivo;
11
+use App\Observers\EventoObserver;
12
+use App\Models\Evento;
11 13
 use App\Models\Attivita;
12 14
 use App\Observers\AttivitaObserver;
15
+use App\Observers\PrenotazioneObserver;
16
+use App\Models\Prenotazione;
17
+use App\Models\SaltacodaOrdine;
18
+use App\Observers\SaltacodaOrdineObserver;
13 19
 use Illuminate\Support\ServiceProvider;
14 20
 use Illuminate\Support\Facades\Vite;
15 21
 
@@ -32,7 +38,11 @@ class AppServiceProvider extends ServiceProvider
32 38
     Dispositivo::observe(DispositivoObserver::class);
33 39
     Pagamento::observe(PagamentoObserver::class);
34 40
     Attivita::observe(AttivitaObserver::class);
41
+    Evento::observe(EventoObserver::class);
42
+    Prenotazione::observe(PrenotazioneObserver::class);
43
+    SaltacodaOrdine::observe(SaltacodaOrdineObserver::class);
35 44
 
45
+    
36 46
     Vite::useStyleTagAttributes(function (?string $src, string $url, ?array $chunk, ?array $manifest) {
37 47
       if ($src !== null) {
38 48
         return [

+ 23
- 15
resources/menu/verticalMenu.json View File

@@ -66,13 +66,6 @@
66 66
     {
67 67
       "menuHeader": "Consulta"
68 68
     },
69
-    {
70
-      "name": "Eventi",
71
-      "icon": "menu-icon icon-base bx bx-calendar-check",
72
-      "slug": "evento.index",
73
-      "url": "admin/evento",
74
-      "can": "permission:view-evento"
75
-    },
76 69
     {
77 70
       "name": "Ordini",
78 71
       "icon": "menu-icon icon-base bx bx-receipt",
@@ -109,6 +102,20 @@
109 102
       "slug": "prenotazione.index",
110 103
       "can": "permission:view-prenotazione",
111 104
       "submenu":[
105
+        {
106
+          "name": "Eventi",
107
+          "icon": "menu-icon icon-base bx bx-sun",
108
+          "slug": "evento.index",
109
+          "url": "admin/evento",
110
+          "can": "permission:view-evento"
111
+        },
112
+        {
113
+          "name": "Prenotazioni",
114
+          "icon": "menu-icon icon-base bx bx-calendar",
115
+          "slug": "prenotazione.index",
116
+          "url": "admin/prenotazione",
117
+          "can": "permission:view-prenotazione"
118
+        },
112 119
         {
113 120
           "name": "Tavoli",
114 121
           "icon": "menu-icon icon-base bx bx-calendar",
@@ -131,13 +138,6 @@
131 138
             }
132 139
           ]
133 140
         },
134
-        {
135
-          "name": "Prenotazioni per evento",
136
-          "icon": "menu-icon icon-base bx bx-calendar",
137
-          "slug": "prenotazione.index",
138
-          "url": "admin/prenotazione",
139
-          "can": "permission:view-prenotazione"
140
-        },
141 141
         {
142 142
           "name": "Prenotazioni da Segresta",
143 143
           "icon": "menu-icon icon-base icon-segresta",
@@ -150,6 +150,13 @@
150 150
     {
151 151
       "menuHeader": "Gestisci"
152 152
     },
153
+    {
154
+      "name": "Cupon",
155
+      "icon": "menu-icon icon-base bx bx-purchase-tag-alt",
156
+      "slug": "cupon.index",
157
+      "url": "admin/cupon",
158
+      "can": "permission:view-cupon | role:amministratore | role:superadmin"
159
+    },
153 160
     {
154 161
       "name": "Contabilità",
155 162
       "icon": "menu-icon icon-base bx bx-chart",
@@ -402,7 +409,8 @@
402 409
       "can": "permission:view-fatturazione | role:amministratore | role:superadmin"
403 410
     },
404 411
     {
405
-      "menuHeader": "Superadmin"
412
+      "menuHeader": "Superadmin",
413
+      "role": "superadmin"
406 414
     },
407 415
     {
408 416
       "name": "Organizzazioni",

+ 2
- 0
resources/views/layouts/sections/menu/verticalMenu.blade.php View File

@@ -1,6 +1,7 @@
1 1
 @php
2 2
 use Illuminate\Support\Facades\Route;
3 3
 use Illuminate\Support\Facades\Session;
4
+use Illuminate\Support\Facades\Auth;
4 5
 $configData = Helper::appClasses();
5 6
 @endphp
6 7
 
@@ -44,6 +45,7 @@ $configData = Helper::appClasses();
44 45
     {{-- adding active and open class if child is active --}}
45 46
 
46 47
     {{-- menu headers --}}
48
+
47 49
     @if (isset($menu->menuHeader))
48 50
     <li class="menu-header small">
49 51
       <span class="menu-header-text">{{ __($menu->menuHeader) }}</span>

+ 83
- 16
routes/web.php View File

@@ -50,7 +50,8 @@ use App\Http\Controllers\RigaFatturazioneController;
50 50
 use App\Http\Controllers\ListinoPrezziController;
51 51
 use App\Http\Controllers\FatturaController;
52 52
 use App\Http\Controllers\AsportoController;
53
-
53
+use App\Http\Controllers\CuponController;
54
+use App\Http\Controllers\EventoPiantinaController;
54 55
 
55 56
 
56 57
 
@@ -84,8 +85,11 @@ Route::group(['middleware' => ['role:superadmin']], function () {
84 85
   Route::resource('fattura', FatturaController::class, ['only' => ['index', 'store']])->names(['index' => 'fattura.index', 'store' => 'fattura.store']);
85 86
   Route::get('fattura/genera-fattura-mensile', [FatturaController::class, 'need_fatturazione_mensile'])->name('fattura.need_fatturazione_mensile');
86 87
   Route::post('fattura/registra-pagamento', [FatturaController::class, 'registra_pagamento'])->name('fattura.registra_pagamento');
88
+  
89
+  //FINE SUPERADMIN
87 90
   });
88 91
 
92
+
89 93
   //Listino prezzi per cliente
90 94
   Route::get('listino-prezzi-cliente', [ListinoPrezziController::class, 'show_listino_cliente'])->name('listino-prezzi-cliente.show');
91 95
 
@@ -129,9 +133,22 @@ Route::group(['middleware' => ['role:superadmin']], function () {
129 133
 
130 134
   // Evento
131 135
   Route::resource('evento', EventoController::class, ['only' => ['index', 'store']]);
136
+  Route::get('evento/admin-show', [EventoController::class, 'admin_show'])->name('evento.admin.show');
132 137
   Route::get('evento/gallery/edit', [EventoController::class, 'gallery_edit'])->name('evento.gallery.edit');
133 138
   Route::post('evento/gallery/upload', [EventoController::class, 'gallery_upload'])->name('evento.gallery.upload');
134 139
   Route::get('evento/edit', [EventoController::class, 'edit'])->name('evento.edit');
140
+  Route::get('evento/geocode-luogo', [EventoController::class, 'geocodeLuogo'])->name('evento.geocode-luogo');
141
+  Route::get('evento/crea', [EventoController::class, 'crea'])->name('evento.crea');
142
+  Route::put('evento/{evento_id}', [EventoController::class, 'update'])->name('evento.update');
143
+  Route::post('evento/{evento_id}/locandina', [EventoController::class, 'uploadLocandina'])->name('evento.locandina.upload');
144
+  Route::delete('evento/{evento_id}/locandina', [EventoController::class, 'destroyLocandina'])->name('evento.locandina.destroy');
145
+  Route::post('evento/{evento_id}/copertina', [EventoController::class, 'uploadCopertina'])->name('evento.copertina.upload');
146
+  Route::delete('evento/{evento_id}/copertina', [EventoController::class, 'destroyCopertina'])->name('evento.copertina.destroy');
147
+  Route::post('evento/preset-domande', [EventoController::class, 'applicaPresetDomande'])->name('evento.preset-domande');
148
+  Route::post('evento/domanda', [EventoController::class, 'storeDomanda'])->name('evento.domanda.store');
149
+  Route::put('evento/domanda/{domanda_id}', [EventoController::class, 'updateDomanda'])->name('evento.domanda.update');
150
+  Route::delete('evento/domanda/{domanda_id}', [EventoController::class, 'destroyDomanda'])->name('evento.domanda.destroy');
151
+  Route::post('evento/domanda/reorder', [EventoController::class, 'reorderDomande'])->name('evento.domanda.reorder');
135 152
 
136 153
   // Evento Form
137 154
   Route::resource('form-evento', EventoFormController::class, ['only' => ['index', 'store']])->names('form-evento');
@@ -144,9 +161,33 @@ Route::group(['middleware' => ['role:superadmin']], function () {
144 161
   // Prenotazione
145 162
   Route::resource('prenotazione', PrenotazioneController::class, ['only' => ['index', 'store']]);
146 163
   Route::get('prenotazione/index/evento', [PrenotazioneController::class, 'index_evento'])->name('prenotazione.index.evento');
164
+  Route::get('prenotazione/nuova', [PrenotazioneController::class, 'nuova'])->name('prenotazione.nuova');
165
+  Route::post('prenotazione/nuova', [PrenotazioneController::class, 'storeNuova'])->name('prenotazione.storeNuova');
166
+  Route::get('prenotazione/edit/{prenotazione_id}', [PrenotazioneController::class, 'edit'])->name('prenotazione.edit');
167
+  Route::post('prenotazione/edit/{prenotazione_id}', [PrenotazioneController::class, 'update'])->name('prenotazione.update');
147 168
   Route::get('prenotazione/show', [PrenotazioneController::class, 'show'])->name('prenotazione.show');
148 169
   Route::get('prenotazione/report/index', [PrenotazioneController::class, 'report_index'])->name('prenotazione.report.index');
149
-  
170
+  Route::get('prenotazione/report/print', [PrenotazioneController::class, 'report_print'])->name('prenotazione.report.print');
171
+  Route::post('prenotazione/conferma' , [PrenotazioneController::class , 'conferma'])->name('prenotazione.conferma');
172
+  Route::post('prenotazione/annulla' , [PrenotazioneController::class , 'annulla'])->name('prenotazione.annulla');
173
+
174
+  // Piantina / sala / tavoli evento
175
+  Route::get('evento/piantina', [EventoPiantinaController::class, 'edit'])->name('evento.piantina.edit');
176
+  Route::post('evento/{evento_id}/piantina/sala', [EventoPiantinaController::class, 'storeSala'])->name('evento.piantina.sala.store');
177
+  Route::put('evento/{evento_id}/piantina/sala', [EventoPiantinaController::class, 'updateSala'])->name('evento.piantina.sala.update');
178
+  Route::delete('evento/{evento_id}/piantina/sala/{sala_id}', [EventoPiantinaController::class, 'destroySala'])->name('evento.piantina.sala.destroy');
179
+  Route::post('evento/{evento_id}/piantina/immagine', [EventoPiantinaController::class, 'uploadPiantina'])->name('evento.piantina.immagine.upload');
180
+  Route::delete('evento/{evento_id}/piantina/immagine', [EventoPiantinaController::class, 'destroyPiantina'])->name('evento.piantina.immagine.destroy');
181
+  Route::post('evento/{evento_id}/piantina/tavolo', [EventoPiantinaController::class, 'storeTavolo'])->name('evento.piantina.tavolo.store');
182
+  Route::put('evento/{evento_id}/piantina/tavolo/{tavolo_id}', [EventoPiantinaController::class, 'updateTavolo'])->name('evento.piantina.tavolo.update');
183
+  Route::delete('evento/{evento_id}/piantina/tavolo/{tavolo_id}', [EventoPiantinaController::class, 'destroyTavolo'])->name('evento.piantina.tavolo.destroy');
184
+  Route::put('evento/{evento_id}/piantina/tavoli/batch', [EventoPiantinaController::class, 'batchTavoli'])->name('evento.piantina.tavolo.batch');
185
+  Route::get('evento/piantina/assegnazioni', [EventoPiantinaController::class, 'assegnazioni'])->name('evento.piantina.assegnazioni');
186
+  Route::post('evento/{evento_id}/piantina/assegna', [EventoPiantinaController::class, 'assegna'])->name('evento.piantina.assegna');
187
+  Route::post('evento/{evento_id}/piantina/assegna-automatico', [EventoPiantinaController::class, 'assegnaAutomatico'])->name('evento.piantina.assegna.automatico');
188
+  Route::delete('evento/{evento_id}/piantina/assegnazione/{assegnazione_id}', [EventoPiantinaController::class, 'rimuoviAssegnazione'])->name('evento.piantina.assegnazione.destroy');
189
+
190
+
150 191
   // Fornitore
151 192
   Route::resource('fornitore', FornitoreController::class, ['only' => ['index', 'store']]);
152 193
   Route::get('fornitore/show', [FornitoreController::class, 'show'])->name('fornitore.show');
@@ -197,19 +238,22 @@ Route::group(['middleware' => ['role:superadmin']], function () {
197 238
   
198 239
   // Prima Nota
199 240
   Route::get('prima-nota/statistiche', [PrimaNotaController::class, 'statistiche'])->name('prima-nota.statistiche');
241
+  Route::get('prima-nota/show', [PrimaNotaController::class, 'show'])->name('prima-nota.show');
200 242
   Route::resource('prima-nota', PrimaNotaController::class, ['only' => ['index', 'store']])->names('prima-nota');
201 243
   
202 244
   // Pagamento
203 245
   Route::resource('pagamento', PagamentoController::class, ['only' => ['index', 'store']]);
204 246
   Route::get('pagamento/show', [PagamentoController::class, 'show'])->name('pagamento.show');
247
+  Route::get('pagamento/show_modal', [PagamentoController::class, 'show_modal'])->name('pagamento.show_modal');
248
+  Route::post('pagamento/storna-pagamento', [PagamentoController::class, 'stornaPagamento'])->name('pagamento.storna-pagamento');
205 249
   
206 250
   // Bilancio
207 251
   Route::resource('bilancio', BilancioController::class, ['only' => ['index', 'store']]);
208 252
   Route::get('bilancio/oggi', [BilancioController::class, 'oggi'])->name('bilancio.oggi');
209 253
   
210 254
   // Report
211
-  Route::resource('report', ReportController::class, ['only' => ['index', 'store']]);
212
-  Route::get('report/movimenti', [ReportController::class, 'movimenti'])->name('report.movimenti');
255
+  Route::resource('report', ReportController::class, ['only' => ['index']]);
256
+  Route::get('report/tab/{tab}', [ReportController::class, 'tab'])->name('report.tab');
213 257
   Route::get('report/export-pdf', [ReportController::class, 'exportPdf'])->name('report.export-pdf');
214 258
 
215 259
 
@@ -311,6 +355,17 @@ Route::post('asporto/postazione/chiamata/{asporto}/completa', [AsportoController
311 355
 Route::get('asporto/postazione/ritiro', [AsportoController::class, 'ritiro'])->name('asporto.postazione.ritiro');
312 356
 Route::post('asporto/postazione/ritiro/{asporto}/completa', [AsportoController::class, 'completaRitiro'])->name('asporto.postazione.ritiro.completa');
313 357
 Route::get('asporto/postazione/{stazione}/sync', [AsportoController::class, 'sync'])->name('asporto.postazione.sync');
358
+
359
+// Cupon
360
+Route::resource('cupon', CuponController::class, ['only' => ['index', 'store']]);
361
+Route::get('cupon/stampa-cupon', [CuponController::class, 'stampaCupon'])->name('cupon.stampa');
362
+Route::post('cupon/genera-batch', [CuponController::class, 'generaBatch'])->name('cupon.genera-batch');
363
+Route::post('cupon/check', [CuponController::class, 'check'])->name('cupon.check');
364
+Route::get('cupon/stampa-cupon/pdf', [CuponController::class, 'pdfCupon'])->name('cupon.stampa.pdf');
365
+Route::get('cupon/stampa-cupon/pdf-personalizzato', [CuponController::class, 'pdfCuponPersonalizzato'])->name('cupon.stampa.pdf-personalizzato');
366
+Route::post('cupon/template/upload', [CuponController::class, 'uploadCuponTemplate'])->name('cupon.template.upload');
367
+Route::post('cupon/stampa-cupon/termica', [CuponController::class, 'printCupon'])->name('cupon.stampa.termica');
368
+Route::get('cupon/checklist-cupon', [CuponController::class, 'checklistCupon'])->name('cupon.checklist-cupon');
314 369
 });
315 370
 
316 371
 
@@ -321,9 +376,16 @@ Route::get('asporto/postazione/{stazione}/sync', [AsportoController::class, 'syn
321 376
 Route::prefix('consulta')->group(function () {
322 377
 // Scontrino per cliente
323 378
 Route::get('index', [ConsultaController::class, 'index'])->name('consulta.index');
324
-Route::get('scontrino/show/{ordine_id}', [ConsultaController::class, 'scontrino_show'])->name('consulta.scontrino.show');
325
-Route::get('comanda/show/{ordine_id}', [ConsultaController::class, 'comanda_show'])->name('consulta.comanda.show');
326
-Route::get('prenotazione/show', [ConsultaController::class, 'prenotazione_show'])->name('consulta.prenotazione.show');
379
+Route::get('scontrino/show/{ordine_codice}', [ConsultaController::class, 'scontrino_show'])->name('consulta.scontrino.show');
380
+Route::get('comanda/show/{ordine_codice}', [ConsultaController::class, 'comanda_show'])->name('consulta.comanda.show');
381
+Route::get('prenotazione/show/{codice}', [ConsultaController::class, 'prenotazione_show'])->middleware('throttle:5,1')->name('consulta.prenotazione.show');
382
+// Route::get('prenotazione/calendario', [ConsultaController::class, 'prenotazione_calendario'])->name('consulta.prenotazione.calendario');
383
+Route::post('prenotazione/richiedi-modifica', [ConsultaController::class, 'prenotazione_richiedi_modifica'])->middleware('throttle:5,1')->name('consulta.prenotazione.richiedi-modifica');
384
+Route::get('prenotazione/modifica/apri', [ConsultaController::class, 'prenotazione_modifica_apri'])->name('consulta.prenotazione.modifica.apri');
385
+Route::get('prenotazione/modifica', [ConsultaController::class, 'prenotazione_modifica_form'])->name('consulta.prenotazione.modifica.form');
386
+Route::post('prenotazione/modifica', [ConsultaController::class, 'prenotazione_modifica_salva'])->name('consulta.prenotazione.modifica.salva');
387
+Route::get('prenotazione/annulla', [ConsultaController::class, 'prenotazione_annulla_form'])->name('consulta.prenotazione.annulla.form');
388
+Route::post('prenotazione/annulla', [ConsultaController::class, 'prenotazione_annulla_conferma'])->name('consulta.prenotazione.annulla.conferma');
327 389
 Route::get('monitor/check-reload', [MonitorController::class, 'checkReload'])->name('consulta.monitor.check-reload');
328 390
 
329 391
 //Listino Prezzi pubblico
@@ -334,12 +396,17 @@ Route::get('listino-prezzi/pdf', [ListinoPrezziController::class, 'export_listin
334 396
 //Rotte per clienti, sena auth
335 397
 Route::prefix('cliente')->group(function(){
336 398
   // Attività
337
-  Route::get('attivita/show', [AttivitaController::class, 'show_public'])->name('cliente.attivita.show');
399
+  Route::get('attivita/show/{slug}', [AttivitaController::class, 'show_public'])->name('cliente.attivita.show');
400
+
401
+  // Prenotazione / Evento (pubblico: identificati da codice)
402
+  Route::get('evento/{codice}', [EventoController::class, 'show'])->name('evento.show');
403
+  Route::get('prenota/{codice}', [PrenotazioneController::class, 'prenota_form'])->name('prenotazone.prenota_form');
404
+  Route::post('prenota/{codice}', [PrenotazioneController::class, 'prenota'])->name('prenotazone.prenota');
405
+
406
+  // Legacy query ?evento_id=… → redirect al codice
407
+  Route::get('evento/show', [EventoController::class, 'showLegacy'])->name('evento.show.legacy');
408
+  Route::get('prenota/form', [PrenotazioneController::class, 'prenotaFormLegacy'])->name('prenotazone.prenota_form.legacy');
338 409
 
339
-  // Prenotazione
340
-  Route::get('prenota/form' , [PrenotazioneController::class , 'prenota_form'])->name('prenotazone.prenota_form'); 
341
-  Route::post('prenota' , [PrenotazioneController::class , 'prenota'])->name('prenotazone.prenota'); 
342
-  Route::get('evento/show', [EventoController::class, 'show'])->name('evento.show');
343 410
   Route::get('testi/show', [TestiController::class, 'show_cliente'])->name('testi.show_cliente');
344 411
   Route::get('punto-vendita', [PuntoVenditaController::class, 'show_cliente'])->name('punto-vendita.cliente.testi.show');
345 412
 
@@ -347,12 +414,12 @@ Route::prefix('cliente')->group(function(){
347 414
   Route::post('avvisami-quando-il-piatto-e-pronto', [RigaOrdineNotificaController::class, 'salva_fcm_token'])->name('riga-ordine-notifica.salva-fcm-token');
348 415
   
349 416
   // Saltacoda
350
-  Route::get('saltacoda/show', [SaltacodaController::class, 'show'])->name('cliente.saltacoda.show');
351
-  Route::post('saltacoda/pre-ordine/salva', [SaltacodaController::class, 'pre_ordine_salva'])->name('saltacoda.pre-ordine.salva');
352
-  Route::get('saltacoda/pre-ordine/show', [SaltacodaController::class, 'pre_ordine_show'])->name('saltacoda.pre-ordine.show');
417
+  Route::get('saltacoda/show/{slug}', [SaltacodaController::class, 'show'])->middleware('throttle:5,1')->name('cliente.saltacoda.show');
418
+  Route::post('saltacoda/pre-ordine/salva', [SaltacodaController::class, 'pre_ordine_salva'])->middleware('throttle:5,1')->name('saltacoda.pre-ordine.salva');
419
+  Route::get('saltacoda/pre-ordine/show', [SaltacodaController::class, 'pre_ordine_show'])->middleware('throttle:5,1')->name('saltacoda.pre-ordine.show');
353 420
 
354 421
   // Tombola (pubblico, per QR)
355
-  Route::get('tombola/{attivita_id}/estratti', [TombolaController::class, 'estratti'])->name('cliente.tombola.estratti');
422
+  Route::get('tombola/{attivita_id}/estratti', [TombolaController::class, 'estratti'])->middleware('throttle:2,1')->name('cliente.tombola.estratti');
356 423
 
357 424
   // Prenotazione Tavolo
358 425
   Route::get('prenota/tavolo' , [PrenotazioneTavoloController::class , 'cliente_index'])->name('cliente.prenotazione-tavolo.index');

Loading…
Cancel
Save