11 Коммиты

Автор SHA1 Сообщение Дата
  marcofalabretti 26459ab1e5 Collega route, observer, menu e comando fest:salute. 2 недель назад
  marcofalabretti 6e9ae1ff56 Report, bilancio e vetrina pubblica attivita. 2 недель назад
  marcofalabretti ab10331a4b Saltacoda: pre-ordine cliente, token e import in cassa. 2 недель назад
  marcofalabretti f657a2bb1b Fatturazione SaaS: utilizzo cassa e saltacoda sul listino. 2 недель назад
  marcofalabretti 91bb1961bf Pagamenti e prima nota: incasso, storno contabile e metodi. 2 недель назад
  marcofalabretti f175056148 Endpoint FestAgent: disattiva allineata e token solo se attivo. 2 недель назад
  marcofalabretti 56122fe46a Stampe: comande cucina, check stampanti e biglietto ritiro. 2 недель назад
  marcofalabretti fdef65ba82 Cassa e carrello: checkout, binding dispositivo e import saltacoda. 2 недель назад
  marcofalabretti ba954866b3 Cupon: generazione, stampa e pagamento in cassa con lock. 2 недель назад
  marcofalabretti 8ee478115f Prenotazioni evento: conferma, mail in coda, piantina tavoli. 2 недель назад
  marcofalabretti fb76759f44 Limita i CRUD admin all'attivita in sessione. 2 недель назад
100 измененных файлов: 7403 добавлений и 1010 удалений
  1. 311
    0
      app/Console/Commands/FestSalute.php
  2. 91
    22
      app/DataTables/AttivitaDataTableEditor.php
  3. 6
    1
      app/DataTables/BachecaDataTable.php
  4. 13
    8
      app/DataTables/BachecaDataTableEditor.php
  5. 14
    8
      app/DataTables/CategoriacontabileDataTableEditor.php
  6. 6
    1
      app/DataTables/ChiusuraServizioDataTable.php
  7. 13
    5
      app/DataTables/ChiusuraServizioDataTableEditor.php
  8. 6
    1
      app/DataTables/ContenutoBachecaDataTable.php
  9. 21
    2
      app/DataTables/ContenutoBachecaDataTableEditor.php
  10. 9
    5
      app/DataTables/CucinaDataTable.php
  11. 37
    12
      app/DataTables/CucinaDataTableEditor.php
  12. 159
    0
      app/DataTables/CuponDataTable.php
  13. 117
    0
      app/DataTables/CuponDataTableEditor.php
  14. 9
    2
      app/DataTables/DispositivoDataTable.php
  15. 15
    12
      app/DataTables/DispositivoDataTableEditor.php
  16. 24
    3
      app/DataTables/EndpointDataTableEditor.php
  17. 68
    44
      app/DataTables/EventoDataTable.php
  18. 24
    4
      app/DataTables/EventoDataTableEditor.php
  19. 17
    9
      app/DataTables/EventoFormDataTableEditor.php
  20. 5
    1
      app/DataTables/FatturaDataTable.php
  21. 15
    8
      app/DataTables/FatturaDataTableEditor.php
  22. 13
    8
      app/DataTables/FornitoreDataTableEditor.php
  23. 13
    9
      app/DataTables/ImpostazioniDataTableEditor.php
  24. 7
    4
      app/DataTables/MetodoPagamentoDataTable.php
  25. 13
    9
      app/DataTables/MetodoPagamentoDataTableEditor.php
  26. 17
    12
      app/DataTables/MonitorDataTableEditor.php
  27. 2
    0
      app/DataTables/OperatoreDataTable.php
  28. 14
    9
      app/DataTables/OperatoreDataTableEditor.php
  29. 32
    4
      app/DataTables/OpzioneFormDataTableEditor.php
  30. 30
    8
      app/DataTables/OrdineDataTableEditor.php
  31. 11
    12
      app/DataTables/PagamentoDataTable.php
  32. 141
    0
      app/DataTables/PagamentoDataTableEditor.php
  33. 12
    12
      app/DataTables/PiattoDataTable.php
  34. 28
    7
      app/DataTables/PiattoDataTableEditor.php
  35. 47
    33
      app/DataTables/PrenotazioneDataTable.php
  36. 47
    14
      app/DataTables/PrenotazioneDataTableEditor.php
  37. 30
    8
      app/DataTables/PrenotazioneTavoloDataTableEditor.php
  38. 9
    6
      app/DataTables/PrimaNotaDataTable.php
  39. 56
    20
      app/DataTables/PrimaNotaDataTableEditor.php
  40. 16
    1
      app/DataTables/PrintJobDataTable.php
  41. 8
    1
      app/DataTables/PuntoOperatoreDataTable.php
  42. 17
    7
      app/DataTables/PuntoOperatoreDataTableEditor.php
  43. 8
    1
      app/DataTables/PuntoVenditaDataTable.php
  44. 17
    14
      app/DataTables/PuntoVenditaDataTableEditor.php
  45. 70
    39
      app/DataTables/RigaFatturazioneDataTable.php
  46. 34
    36
      app/DataTables/RigaFatturazioneDataTableEditor.php
  47. 19
    14
      app/DataTables/StampanteDataTableEditor.php
  48. 7
    4
      app/DataTables/TavoloDataTable.php
  49. 13
    10
      app/DataTables/TavoloDataTableEditor.php
  50. 13
    10
      app/DataTables/TestiDataTableEditor.php
  51. 10
    5
      app/DataTables/VariantePiattoDataTable.php
  52. 36
    9
      app/DataTables/VariantePiattoDataTableEditor.php
  53. 2
    0
      app/Http/Controllers/AllergeneController.php
  54. 13
    0
      app/Http/Controllers/AsportoController.php
  55. 46
    9
      app/Http/Controllers/AttivitaController.php
  56. 9
    1
      app/Http/Controllers/BachecaController.php
  57. 14
    4
      app/Http/Controllers/BachecaHasContenutoController.php
  58. 15
    4
      app/Http/Controllers/BilancioController.php
  59. 114
    72
      app/Http/Controllers/CarrelloController.php
  60. 2
    0
      app/Http/Controllers/CategoriaContabileController.php
  61. 3
    1
      app/Http/Controllers/ChiusuraServizioController.php
  62. 380
    18
      app/Http/Controllers/ConsultaController.php
  63. 7
    0
      app/Http/Controllers/ContenutoBachecaController.php
  64. 14
    3
      app/Http/Controllers/Controller.php
  65. 3
    1
      app/Http/Controllers/CucinaController.php
  66. 395
    0
      app/Http/Controllers/CuponController.php
  67. 4
    0
      app/Http/Controllers/DispositivoController.php
  68. 86
    30
      app/Http/Controllers/EndpointController.php
  69. 696
    13
      app/Http/Controllers/EventoController.php
  70. 2
    0
      app/Http/Controllers/EventoFormController.php
  71. 834
    0
      app/Http/Controllers/EventoPiantinaController.php
  72. 10
    2
      app/Http/Controllers/FatturaController.php
  73. 6
    1
      app/Http/Controllers/FornitoreController.php
  74. 5
    1
      app/Http/Controllers/ImpostazioniController.php
  75. 5
    4
      app/Http/Controllers/ListinoPrezziController.php
  76. 13
    4
      app/Http/Controllers/MappaDispositiviController.php
  77. 3
    1
      app/Http/Controllers/MetodoPagamentoController.php
  78. 25
    2
      app/Http/Controllers/MonitorController.php
  79. 26
    3
      app/Http/Controllers/OperatoreController.php
  80. 24
    2
      app/Http/Controllers/OrdineController.php
  81. 107
    14
      app/Http/Controllers/PagamentoController.php
  82. 10
    1
      app/Http/Controllers/PiattoController.php
  83. 1326
    49
      app/Http/Controllers/PrenotazioneController.php
  84. 15
    3
      app/Http/Controllers/PrenotazioneTavoloController.php
  85. 22
    3
      app/Http/Controllers/PrimaNotaController.php
  86. 12
    2
      app/Http/Controllers/PrintJobController.php
  87. 6
    1
      app/Http/Controllers/PuntoOperatoreController.php
  88. 85
    38
      app/Http/Controllers/PuntoVenditaController.php
  89. 916
    166
      app/Http/Controllers/ReportController.php
  90. 2
    0
      app/Http/Controllers/RigaFatturazioneController.php
  91. 13
    9
      app/Http/Controllers/RigaOrdineController.php
  92. 2
    2
      app/Http/Controllers/RigaOrdineNotificaController.php
  93. 3
    1
      app/Http/Controllers/RoleController.php
  94. 334
    60
      app/Http/Controllers/SaltacodaController.php
  95. 2
    0
      app/Http/Controllers/StampanteController.php
  96. 2
    0
      app/Http/Controllers/TavoloController.php
  97. 9
    2
      app/Http/Controllers/TestiController.php
  98. 8
    8
      app/Http/Controllers/TombolaController.php
  99. 3
    1
      app/Http/Controllers/UserController.php
  100. 0
    0
      app/Http/Controllers/VariantePiattoController.php

+ 311
- 0
app/Console/Commands/FestSalute.php Просмотреть файл

@@ -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
+}

+ 91
- 22
app/DataTables/AttivitaDataTableEditor.php Просмотреть файл

@@ -8,6 +8,8 @@ use Illuminate\Validation\Rule;
8 8
 use Yajra\DataTables\DataTablesEditor;
9 9
 use Illuminate\Http\Request;
10 10
 use Illuminate\Validation\ValidationException;
11
+use Illuminate\Http\UploadedFile;
12
+use Illuminate\Support\Facades\Auth;
11 13
 use Illuminate\Support\Facades\Storage;
12 14
 use Illuminate\Support\Str;
13 15
 use Illuminate\Http\JsonResponse;
@@ -83,40 +85,83 @@ class AttivitaDataTableEditor extends DataTablesEditor
83 85
 
84 86
   public function creating(Model $model, array $data): array
85 87
   {
86
-    // $model->roles()->sync([$data['ruolo_id']]);
87 88
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
89
+    $data['user_id'] = Auth::id();
90
+
88 91
     return $data;
89 92
   }
90 93
 
91 94
   public function updating(Model $model, array $data): array
92 95
   {
93
-    // dd($data['ruolo']);
94
-    // $model->roles()->sync([$data['ruolo_id']]);
96
+    $this->garantisciQuestaAttivita($model);
95 97
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
98
+    unset($data['user_id']);
99
+
96 100
     return $data;
97 101
   }
98 102
 
99
-  public function created(Model $model, array $data): Model
103
+  public function deleting(Model $model, array $data): array
100 104
   {
101
-    return $model;
105
+    $this->garantisciQuestaAttivita($model);
106
+
107
+    return $data;
108
+  }
109
+
110
+  private function garantisciQuestaAttivita(Model $model): void
111
+  {
112
+    $user = Auth::user();
113
+    if ($user?->hasRole('superadmin')) {
114
+      return;
115
+    }
116
+
117
+    if (! $model instanceof Attivita || (int) $model->user_id !== (int) $user?->id) {
118
+      abort(404);
119
+    }
120
+  }
121
+
122
+  public function uploadRules(): array
123
+  {
124
+    $image = ['required', 'file', 'image', 'mimes:jpeg,png,jpg,gif,webp', 'max:5120'];
125
+
126
+    return [
127
+      'path_logo' => $image,
128
+      'path_icon' => $image,
129
+      'path_image' => $image,
130
+    ];
102 131
   }
103 132
 
104 133
   public function upload(Request $request): JsonResponse
105 134
   {
106 135
     $this->action = 'upload';
107 136
 
108
-    $field   = $request->input('uploadField');
109
-    $storage = Storage::disk($this->disk);
137
+    $field = $request->input('uploadField');
138
+    if (! $field || ! is_string($field)) {
139
+      $field = 'file';
140
+    }
110 141
 
111 142
     try {
112
-      $rules      = $this->uploadRules();
113
-      $fieldRules = ['upload' => data_get($rules, $field, [])];
143
+      $storage = Storage::disk($this->disk);
144
+      $rules = $this->uploadRules();
145
+      $fieldRules = ['upload' => $rules[$field] ?? $rules['path_image']];
114 146
 
115 147
       $this->validate($request, $fieldRules, $this->messages(), $this->attributes());
116 148
 
117 149
       $uploadedFile = $request->file('upload');
118
-      $filename     = $this->getUploadedFilename($field, $uploadedFile);
119
-      $id           = $storage->putFileAs($request->id, $uploadedFile, $filename);
150
+      if (! $uploadedFile instanceof UploadedFile) {
151
+        throw ValidationException::withMessages([
152
+          'upload' => 'File non valido.',
153
+        ]);
154
+      }
155
+
156
+      $directory = $this->resolveUploadDirectory($request);
157
+      $filename = $this->getUploadedFilename($field, $uploadedFile);
158
+      $id = $storage->putFileAs($directory, $uploadedFile, $filename);
159
+
160
+      if (! is_string($id)) {
161
+        throw ValidationException::withMessages([
162
+          'upload' => 'Impossibile salvare il file caricato.',
163
+        ]);
164
+      }
120 165
 
121 166
       if (method_exists($this, 'uploaded')) {
122 167
         $id = $this->uploaded($id);
@@ -124,16 +169,16 @@ class AttivitaDataTableEditor extends DataTablesEditor
124 169
 
125 170
       return response()->json([
126 171
         'action' => $this->action,
127
-        'data'   => [],
128
-        'files'  => [
172
+        'data' => [],
173
+        'files' => [
129 174
           'files' => [
130 175
             $id => [
131
-              'filename'      => $id,
176
+              'filename' => $id,
132 177
               'original_name' => $uploadedFile->getClientOriginalName(),
133
-              'size'          => $uploadedFile->getSize(),
134
-              'directory'     => $request->id,
135
-              'disk'          => $this->disk,
136
-              'url'           => $storage->url($id),
178
+              'size' => $uploadedFile->getSize(),
179
+              'directory' => $directory,
180
+              'disk' => $this->disk,
181
+              'url' => $storage->url($id),
137 182
             ],
138 183
           ],
139 184
         ],
@@ -143,18 +188,42 @@ class AttivitaDataTableEditor extends DataTablesEditor
143 188
       ]);
144 189
     } catch (ValidationException $exception) {
145 190
       return response()->json([
146
-        'action'      => $this->action,
147
-        'data'        => [],
191
+        'action' => $this->action,
192
+        'data' => [],
148 193
         'fieldErrors' => [
149 194
           [
150
-            'name'   => $field,
151
-            'status' => str_replace('upload', $field, $exception->errors()['upload'][0]),
195
+            'name' => $field,
196
+            'status' => str_replace('upload', $field, (string) ($exception->errors()['upload'][0] ?? 'Errore di validazione')),
152 197
           ],
153 198
         ],
154 199
       ]);
155 200
     }
156 201
   }
157 202
 
203
+  protected function resolveUploadDirectory(Request $request): string
204
+  {
205
+    $id = $request->input('id');
206
+    if ($id === null || $id === '' || ! is_numeric($id)) {
207
+      return 'tmp';
208
+    }
209
+
210
+    $attivita = Attivita::find((int) $id);
211
+    if (! $attivita) {
212
+      abort(404);
213
+    }
214
+
215
+    $this->garantisciQuestaAttivita($attivita);
216
+
217
+    return (string) $attivita->id;
218
+  }
219
+
220
+  protected function getUploadedFilename(string $field, UploadedFile $uploadedFile): string
221
+  {
222
+    $ext = $uploadedFile->getClientOriginalExtension();
223
+
224
+    return $field.'_'.time().'_'.Str::random(4).($ext !== '' ? '.'.$ext : '');
225
+  }
226
+
158 227
   public function messages(): array
159 228
   {
160 229
     return $this->messages;

+ 6
- 1
app/DataTables/BachecaDataTable.php Просмотреть файл

@@ -43,7 +43,12 @@ class BachecaDataTable extends DataTable
43 43
      */
44 44
     public function query(Bacheca $model): QueryBuilder
45 45
     {
46
-        return $model->newQuery()->where('attivita_id', $this->attivita_id);
46
+        $attivitaId = (int) $this->attivita_id;
47
+        if ($attivitaId <= 0) {
48
+            return $model->newQuery()->whereRaw('1 = 0');
49
+        }
50
+
51
+        return $model->newQuery()->where('attivita_id', $attivitaId);
47 52
     }
48 53
 
49 54
     /**

+ 13
- 8
app/DataTables/BachecaDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Bacheca;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 10
 
14 11
 class BachecaDataTableEditor extends DataTablesEditor
15 12
 {
@@ -76,18 +73,26 @@ class BachecaDataTableEditor extends DataTablesEditor
76 73
 
77 74
   public function creating(Model $model, array $data): array
78 75
   {
79
-    // $model->roles()->sync([$data['ruolo_id']]);
76
+    $data['attivita_id'] = Session::get('attivita_attuale');
77
+    AttivitaService::garantisciAttivita($data['attivita_id']);
80 78
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
81 79
     return $data;
82 80
   }
83 81
 
84 82
   public function updating(Model $model, array $data): array
85 83
   {
86
-    // dd($data['ruolo']);
87
-    // $model->roles()->sync([$data['ruolo_id']]);
84
+    AttivitaService::garantisciAttivita($model->attivita_id);
85
+    unset($data['attivita_id']);
88 86
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
89 87
     return $data;
90 88
   }
89
+
90
+  public function deleting(Model $model, array $data): array
91
+  {
92
+    AttivitaService::garantisciAttivita($model->attivita_id);
93
+
94
+    return $data;
95
+  }
91 96
   public function messages(): array
92 97
   {
93 98
     return $this->messages;

+ 14
- 8
app/DataTables/CategoriacontabileDataTableEditor.php Просмотреть файл

@@ -3,13 +3,11 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Categoriacontabile;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
8
+use Illuminate\Support\Facades\Session;
7 9
 use Illuminate\Validation\Rule;
8 10
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 11
 
14 12
 class CategoriacontabileDataTableEditor extends DataTablesEditor
15 13
 {
@@ -35,7 +33,7 @@ class CategoriacontabileDataTableEditor extends DataTablesEditor
35 33
       'nome'  => [
36 34
         'required',
37 35
         Rule::unique('categoria_contabile', 'nome')
38
-            ->where('attivita_id', $data['attivita_id'] ?? null),
36
+            ->where('attivita_id', Session::get('attivita_attuale')),
39 37
       ],
40 38
       'descrizione' => 'nullable',
41 39
       'is_attiva' => 'boolean',
@@ -83,18 +81,26 @@ class CategoriacontabileDataTableEditor extends DataTablesEditor
83 81
 
84 82
   public function creating(Model $model, array $data): array
85 83
   {
86
-    // $model->roles()->sync([$data['ruolo_id']]);
84
+    $data['attivita_id'] = Session::get('attivita_attuale');
85
+    AttivitaService::garantisciAttivita($data['attivita_id']);
87 86
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
88 87
     return $data;
89 88
   }
90 89
 
91 90
   public function updating(Model $model, array $data): array
92 91
   {
93
-    // dd($data['ruolo']);
94
-    // $model->roles()->sync([$data['ruolo_id']]);
92
+    AttivitaService::garantisciAttivita($model->attivita_id);
93
+    unset($data['attivita_id']);
95 94
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
96 95
     return $data;
97 96
   }
97
+
98
+  public function deleting(Model $model, array $data): array
99
+  {
100
+    AttivitaService::garantisciAttivita($model->attivita_id);
101
+
102
+    return $data;
103
+  }
98 104
   public function messages(): array
99 105
   {
100 106
     return $this->messages;

+ 6
- 1
app/DataTables/ChiusuraServizioDataTable.php Просмотреть файл

@@ -54,7 +54,12 @@ class ChiusuraServizioDataTable extends DataTable
54 54
      */
55 55
     public function query(ChiusuraServizio $model): QueryBuilder
56 56
     {
57
-        return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('chiusura_at', 'desc');
57
+        $attivitaId = (int) $this->attivita_id;
58
+        if ($attivitaId <= 0) {
59
+            return $model->newQuery()->whereRaw('1 = 0');
60
+        }
61
+
62
+        return $model->newQuery()->where('attivita_id', $attivitaId)->orderBy('chiusura_at', 'desc');
58 63
     }
59 64
 
60 65
     /**

+ 13
- 5
app/DataTables/ChiusuraServizioDataTableEditor.php Просмотреть файл

@@ -3,11 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\ChiusuraServizio;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11 10
 
12 11
 
13 12
 class ChiusuraServizioDataTableEditor extends DataTablesEditor
@@ -29,7 +28,6 @@ class ChiusuraServizioDataTableEditor extends DataTablesEditor
29 28
   public function createRules(): array
30 29
   {
31 30
     return [
32
-      'attivita_id'  => 'required',
33 31
       'chiusura_at' => 'required|date',
34 32
       'user_id' => 'required',
35 33
       'note' => 'nullable',
@@ -49,7 +47,6 @@ class ChiusuraServizioDataTableEditor extends DataTablesEditor
49 47
   public function editRules(Model $model): array
50 48
   {
51 49
     return [
52
-      'attivita_id'  => 'required',
53 50
       'chiusura_at' => 'required|date',
54 51
       'note' => 'nullable',
55 52
       'info' => 'nullable',
@@ -73,11 +70,22 @@ class ChiusuraServizioDataTableEditor extends DataTablesEditor
73 70
 
74 71
   public function creating(Model $model, array $data): array
75 72
   {
73
+    $data['attivita_id'] = Session::get('attivita_attuale');
74
+    AttivitaService::garantisciAttivita($data['attivita_id']);
76 75
     return $data;
77 76
   }
78 77
 
79 78
   public function updating(Model $model, array $data): array
80 79
   {
80
+    AttivitaService::garantisciAttivita($model->attivita_id);
81
+    unset($data['attivita_id']);
82
+    return $data;
83
+  }
84
+
85
+  public function deleting(Model $model, array $data): array
86
+  {
87
+    AttivitaService::garantisciAttivita($model->attivita_id);
88
+
81 89
     return $data;
82 90
   }
83 91
   public function messages(): array

+ 6
- 1
app/DataTables/ContenutoBachecaDataTable.php Просмотреть файл

@@ -46,7 +46,12 @@ class ContenutoBachecaDataTable extends DataTable
46 46
      */
47 47
     public function query(ContenutoBacheca $model): QueryBuilder
48 48
     {
49
-        $model = $model->newQuery()->where('attivita_id', $this->attivita_id);
49
+        $attivitaId = (int) $this->attivita_id;
50
+        if ($attivitaId <= 0) {
51
+            return $model->newQuery()->whereRaw('1 = 0');
52
+        }
53
+
54
+        $model = $model->newQuery()->where('attivita_id', $attivitaId);
50 55
         if($this->bacheca_id){
51 56
             return $model->join('bacheca_has_contenuto', 'contenuto_bacheca.id', '=', 'bacheca_has_contenuto.contenuto_id')->where('bacheca_has_contenuto.bacheca_id', $this->bacheca_id);
52 57
         }

+ 21
- 2
app/DataTables/ContenutoBachecaDataTableEditor.php Просмотреть файл

@@ -3,8 +3,9 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\ContenutoBacheca;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9 10
 use Illuminate\Http\Request;
10 11
 use Illuminate\Validation\ValidationException;
@@ -79,11 +80,21 @@ class ContenutoBachecaDataTableEditor extends DataTablesEditor
79 80
 
80 81
   public function creating(Model $model, array $data): array
81 82
   {
83
+    $data['attivita_id'] = Session::get('attivita_attuale');
84
+    AttivitaService::garantisciAttivita($data['attivita_id']);
82 85
     return $data;
83 86
   }
84 87
 
85 88
   public function updating(Model $model, array $data): array
86 89
   {
90
+    AttivitaService::garantisciAttivita($model->attivita_id);
91
+    unset($data['attivita_id']);
92
+    return $data;
93
+  }
94
+
95
+  public function deleting(Model $model, array $data): array
96
+  {
97
+    AttivitaService::garantisciAttivita($model->attivita_id);
87 98
 
88 99
     return $data;
89 100
   }
@@ -107,7 +118,15 @@ class ContenutoBachecaDataTableEditor extends DataTablesEditor
107 118
 
108 119
       $uploadedFile = $request->file('upload');
109 120
       $filename     = $this->getUploadedFilename($field, $uploadedFile);
110
-      $id           = $storage->putFileAs($request->id, $uploadedFile, $filename);
121
+      $rowId        = $request->id;
122
+      if ($rowId !== null && $rowId !== '' && is_numeric($rowId)) {
123
+        $contenuto = ContenutoBacheca::find((int) $rowId);
124
+        if (! $contenuto) {
125
+          abort(404);
126
+        }
127
+        AttivitaService::garantisciAttivita($contenuto->attivita_id);
128
+      }
129
+      $id           = $storage->putFileAs($rowId, $uploadedFile, $filename);
111 130
 
112 131
       if (method_exists($this, 'uploaded')) {
113 132
         $id = $this->uploaded($id);

+ 9
- 5
app/DataTables/CucinaDataTable.php Просмотреть файл

@@ -79,11 +79,12 @@ class CucinaDataTable extends DataTable
79 79
      */
80 80
     public function query(Cucina $model): QueryBuilder
81 81
     {
82
-        if($this->attivita_id){
83
-            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('nome', 'asc');
84
-        }else{
82
+        $attivitaId = (int) $this->attivita_id;
83
+        if ($attivitaId <= 0) {
85 84
             return $model->newQuery()->whereRaw('1 = 0');
86 85
         }
86
+
87
+        return $model->newQuery()->where('attivita_id', $attivitaId)->orderBy('nome', 'asc');
87 88
     }
88 89
 
89 90
     /**
@@ -117,13 +118,14 @@ class CucinaDataTable extends DataTable
117 118
                         Editor::make()
118 119
                         ->ajax(route('cucina.store'))
119 120
                         ->fields([
120
-                          Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
121
+                          Fields\Hidden::make('attivita_id')->label('Attività')->default((int) $this->attivita_id),
121 122
                           Fields\Boolean::make('is_attiva')->label('Attiva')->default(true),  
122 123
                           Fields\Text::make('nome')->label('Nome'),
123 124
                           Fields\Text::make('descrizione')->label('Descrizione'),
124
-                          Fields\Select2::make('stampante_id')->label('Stampante')->options(Dispositivo::where('tipo', Dispositivo::STAMPANTE)->pluck('id', 'nome')),
125
+                          Fields\Select2::make('stampante_id')->label('Stampante')->options(Dispositivo::where('tipo', Dispositivo::STAMPANTE)->where('attivita_id', (int) $this->attivita_id)->pluck('id', 'nome')),
125 126
                           Fields\Text::make('colore')->label('Colore')->set('attr', ['type' => 'color']),
126 127
                           Fields\Boolean::make('coperto_come_piatto')->label('Ogni piatto ordinato corrisponde ad un coperto'),  
128
+                          Fields\Boolean::make('stampa_ritiro')->label('Stampa biglietto per ritiro ordine'),
127 129
                             // Fields\Image::make('immagine')->label('Immagine'),
128 130
                             // Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::where('is_attiva', true)->pluck('id', 'nome')),
129 131
                         ])
@@ -153,6 +155,7 @@ class CucinaDataTable extends DataTable
153 155
         Column::make('badge_colore')->title('Cucina')->addClass('text-left')->responsivePriority(1),
154 156
         Column::computed('piatti_count')->title('Piatti')->addClass('text-center'),
155 157
         Column::make('coperto_come_piatto')->visible(false),
158
+        Column::make('stampa_ritiro')->visible(false),
156 159
         Column::computed('action')
157 160
         ->title('')
158 161
         ->exportable(false)
@@ -174,6 +177,7 @@ class CucinaDataTable extends DataTable
174 177
             Column::make('stampante_id')->data('stampante_display')->title('Stampante')->addClass('text-center'),
175 178
             // Column::make('cucina_id')->data('cucina_id_display')->title('Cucina')->addClass('text-center'),
176 179
             Column::make('coperto_come_piatto')->visible(false),
180
+            Column::make('stampa_ritiro')->visible(false),
177 181
             Column::make('action')
178 182
             ->title('')
179 183
             ->exportable(false)

+ 37
- 12
app/DataTables/CucinaDataTableEditor.php Просмотреть файл

@@ -3,13 +3,11 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Cucina;
6
+use App\Models\Dispositivo;
7
+use App\Services\Attivita\AttivitaService;
6 8
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
10
+use Illuminate\Support\Facades\Session;
13 11
 
14 12
 class CucinaDataTableEditor extends DataTablesEditor
15 13
 {
@@ -77,26 +75,53 @@ class CucinaDataTableEditor extends DataTablesEditor
77 75
 
78 76
   public function creating(Model $model, array $data): array
79 77
   {
80
-    // $model->roles()->sync([$data['ruolo_id']]);
78
+    $data['attivita_id'] = Session::get('attivita_attuale');
79
+    AttivitaService::garantisciAttivita($data['attivita_id']);
80
+    $this->garantisciStampanteDiQuestaAttivita($data['stampante_id'] ?? null, $data['attivita_id']);
81
+
81 82
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
82
-    
83 83
     $data['info']['coperto_come_piatto'] = filter_var($data['coperto_come_piatto'] ?? false, FILTER_VALIDATE_BOOLEAN);
84
-    $data['info']['colore'] = $data['colore'];
84
+    $data['info']['stampa_ritiro'] = filter_var($data['stampa_ritiro'] ?? false, FILTER_VALIDATE_BOOLEAN);
85
+    $data['info']['colore'] = $data['colore'] ?? null;
85 86
 
86
-    // $data['info']['coperto_come_piatto'] = isset($data['coperto_come_piatto']) ? true : false;
87 87
     return $data;
88 88
   }
89 89
 
90 90
   public function updating(Model $model, array $data): array
91 91
   {
92
-    // dd($data['ruolo']);
93
-    // $model->roles()->sync([$data['ruolo_id']]);
92
+    AttivitaService::garantisciAttivita($model->attivita_id);
93
+    unset($data['attivita_id']);
94
+    $this->garantisciStampanteDiQuestaAttivita($data['stampante_id'] ?? $model->stampante_id, $model->attivita_id);
95
+
94 96
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
95
-    $data['info']['colore'] = $data['colore'];
97
+    $data['info']['colore'] = $data['colore'] ?? ($model->info['colore'] ?? null);
96 98
     $data['info']['coperto_come_piatto'] = filter_var($data['coperto_come_piatto'] ?? false, FILTER_VALIDATE_BOOLEAN);
99
+    $data['info']['stampa_ritiro'] = filter_var($data['stampa_ritiro'] ?? false, FILTER_VALIDATE_BOOLEAN);
100
+    return $data;
101
+  }
102
+
103
+  public function deleting(Model $model, array $data): array
104
+  {
105
+    AttivitaService::garantisciAttivita($model->attivita_id);
97 106
 
98 107
     return $data;
99 108
   }
109
+
110
+  private function garantisciStampanteDiQuestaAttivita($stampanteId, $attivitaId): void
111
+  {
112
+    if (! $stampanteId) {
113
+      return;
114
+    }
115
+
116
+    $stampante = Dispositivo::find($stampanteId);
117
+    if (
118
+      ! $stampante
119
+      || (int) $stampante->attivita_id !== (int) $attivitaId
120
+      || $stampante->tipo !== Dispositivo::STAMPANTE
121
+    ) {
122
+      abort(404);
123
+    }
124
+  }
100 125
   public function messages(): array
101 126
   {
102 127
     return $this->messages;

+ 159
- 0
app/DataTables/CuponDataTable.php Просмотреть файл

@@ -0,0 +1,159 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\Cupon;
6
+use Illuminate\Database\Eloquent\Builder as QueryBuilder;
7
+use Yajra\DataTables\EloquentDataTable;
8
+use Yajra\DataTables\Html\Builder as HtmlBuilder;
9
+use Yajra\DataTables\Html\Button;
10
+use Yajra\DataTables\Html\Column;
11
+use Yajra\DataTables\Html\Editor\Editor;
12
+use Yajra\DataTables\Html\Editor\Fields;
13
+use Yajra\DataTables\Services\DataTable;
14
+use Illuminate\Support\Facades\Auth;
15
+use Illuminate\Support\Str;
16
+
17
+
18
+class CuponDataTable extends DataTable
19
+{
20
+
21
+ public function __construct()
22
+ {
23
+    $this->dataTableVariable = 'dataTable_cupon';
24
+ }
25
+    /**
26
+     * Build the DataTable class.
27
+     *
28
+     * @param QueryBuilder<Cupon> $query Results from query() method.
29
+     */
30
+    public function dataTable(QueryBuilder $query): EloquentDataTable
31
+    {
32
+        return (new EloquentDataTable($query))
33
+            ->addColumn('action', function ($entity) {
34
+                return view('cupon.menu', compact('entity'));
35
+            })
36
+            ->editColumn('importo', function ($entity) {
37
+                return '€ ' . number_format($entity->importo, 2, ',', '.');
38
+            })
39
+            ->editColumn('validita_display', function ($entity) {
40
+                if($entity->validita_da->isSameDay($entity->validita_a)){
41
+                    return $entity->validita_da->format('d/m/Y');
42
+                }else{
43
+                    return $entity->validita_da->format('d/m/Y') . ' - ' . $entity->validita_a->format('d/m/Y');
44
+                }   
45
+            })
46
+            ->addColumn('stato_display', function ($entity) {
47
+                return view('cupon.stato', ['stato' => $entity->stato]);
48
+            })
49
+            ->addColumn('codice_display', function ($entity) {
50
+                return view('cupon.stato', ['codice' => $entity->codice]);
51
+            })
52
+            ->setRowId('id');
53
+    }
54
+
55
+    /**
56
+     * Get the query source of dataTable.
57
+     *
58
+     * @return QueryBuilder<Cupon>
59
+     */
60
+    public function query(Cupon $model): QueryBuilder
61
+    {
62
+        $attivitaId = (int) $this->attivita_id;
63
+        if ($attivitaId <= 0) {
64
+            return $model->newQuery()->whereRaw('1 = 0');
65
+        }
66
+
67
+        return $model->newQuery()->where('attivita_id', $attivitaId);
68
+    }
69
+
70
+    /**
71
+     * Optional method if you want to use the html builder.
72
+     */
73
+    public function html(): HtmlBuilder
74
+    {
75
+        $buttons = [];
76
+
77
+        if(Auth::user()->can('create-cupon')){
78
+            array_push($buttons, Button::make('create')
79
+            ->editor('editor')
80
+            ->formTitle('Crea nuovo cupon')
81
+            ->className('btn btn-sm btn-primary mb-4 text-white')
82
+            ->text('<i class="fas fa-plus "></i> Nuovo cupon')
83
+            );
84
+        
85
+
86
+            array_push($buttons, Button::raw('generaBatch')
87
+            ->className('btn btn-sm btn-primary mb-4 text-white')
88
+            ->text('<i class="fas fa-plus "></i> massivo')
89
+            ->action("generaBatchCupon()")
90
+            );
91
+
92
+            // array_push($buttons, Button::raw('reportCupon')
93
+            // ->className('btn btn-sm btn-primary mb-4 text-white')
94
+            // ->text('<i class="fas fa-file-alt "></i> Report cupon')
95
+            // ->action("reportCupon()")
96
+            // );
97
+            
98
+            array_push($buttons, Button::raw('stampaCupon')
99
+            ->className('btn btn-sm btn-primary mb-4 text-white')
100
+            ->text('<i class="fas fa-file-alt "></i> Stampa cupon')
101
+            ->action("window.location.href='".route('cupon.stampa')."'")
102
+            );
103
+        }
104
+
105
+        return $this->builder()
106
+                    ->setTableId($this->dataTableVariable)
107
+                    ->columns($this->getColumns())
108
+                    ->minifiedAjax()
109
+                    ->orderBy(1)
110
+                    ->selectStyleSingle()
111
+                    ->buttons($buttons)
112
+                    ->initComplete("function(settings, json){
113
+                        initComplete_cupon();
114
+                    }")
115
+                    ->language(asset('assets/Italian.json'))
116
+                    ->dom(count($buttons)==0?'rtip':'Bfrtip')
117
+                    ->editor(
118
+                        Editor::make()->fields([
119
+                        Fields\Hidden::make('attivita_id')->label('Attività')->default((int) $this->attivita_id),
120
+                        Fields\Hidden::make('stato')->label('Stato')->default(Cupon::GENERATO),
121
+                        Fields\Hidden::make('codice')->label('Codice'),
122
+                        Fields\Number::make('importo')->label('Importo')->required(),
123
+                        Fields\Text::make('nominativo')->label('Nominativo')->required(),
124
+                        Fields\Text::make('email')->label('Email'),
125
+                        Fields\Date::make('validita_da')->label('Validità da')->required(),
126
+                        Fields\Date::make('validita_a')->label('Validità a')->required(),
127
+                    ]));
128
+    }
129
+
130
+    /**
131
+     * Get the dataTable columns definition.
132
+     */
133
+    public function getColumns(): array
134
+    {
135
+        return [
136
+            Column::make('id'),
137
+            Column::make('codice_display')->title('Codice'),
138
+            Column::make('stato_display'),
139
+            Column::make('importo')->title('Importo'),
140
+            Column::make('nominativo')->title('Nominativo'),
141
+            // Column::make('email'),
142
+            Column::make('validita_display')->title('Validità'),
143
+            Column::computed('action')
144
+                  ->title('Azioni')
145
+                  ->exportable(false)
146
+                  ->printable(false)
147
+                  ->width(60)
148
+                  ->addClass('text-center'),
149
+        ];
150
+    }
151
+
152
+    /**
153
+     * Get the filename for export.
154
+     */
155
+    protected function filename(): string
156
+    {
157
+        return 'Cupon_' . date('YmdHis');
158
+    }
159
+}

+ 117
- 0
app/DataTables/CuponDataTableEditor.php Просмотреть файл

@@ -0,0 +1,117 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\Cupon;
6
+use App\Services\Attivita\AttivitaService;
7
+use Illuminate\Database\Eloquent\Model;
8
+use Yajra\DataTables\DataTablesEditor;
9
+use Illuminate\Support\Facades\Session;
10
+
11
+class CuponDataTableEditor extends DataTablesEditor
12
+{
13
+  protected $model = Cupon::class;
14
+  // protected $uploadDir = '';
15
+  // protected $disk = 'modelliRicevute';
16
+
17
+  protected $messages = [
18
+    'codice.required' => 'Il codice è richiesto',
19
+    'codice.unique' => 'Il codice deve essere unico',
20
+    'validita_a.after_or_equal' => 'La validità a deve essere dopo la validità da',
21
+    'validita_da.date' => 'La validità da deve essere una data valida',
22
+    'validita_a.date' => 'La validità a deve essere una data valida',
23
+    'importo.numeric' => 'L\'importo deve essere un numero',
24
+    'importo.min' => 'L\'importo deve essere maggiore di 0',
25
+    'nominativo.string' => 'Il nominativo deve essere una stringa',
26
+    'nominativo.max' => 'Il nominativo deve essere massimo 255 caratteri',
27
+    'email.email' => 'L\'email deve essere una email valida',
28
+  ];
29
+
30
+  /**
31
+  * Get create action validation rules.
32
+  *
33
+  * @return array
34
+  */
35
+  public function createRules(): array
36
+  {
37
+    return [
38
+      // 'codice'  => 'required|unique:cupon,codice',
39
+      'importo' => 'nullable|numeric|min:0',
40
+      'nominativo' => 'nullable|string|max:255',
41
+      'email' => 'nullable|email|max:255',
42
+      'validita_da' => 'nullable|date',
43
+      'validita_a' => 'nullable|date|after_or_equal:validita_da',
44
+    ];
45
+  }
46
+
47
+  public function createMessages(): array{
48
+    return $this->messages;
49
+  }
50
+
51
+  /**
52
+  * Get edit action validation rules.
53
+  *
54
+  * @param Model $model
55
+  * @return array
56
+  */
57
+  public function editRules(Model $model): array
58
+  {
59
+    return [
60
+      'codice'  => 'required|unique:cupon,codice,' . $model->id,
61
+      'importo' => 'nullable|numeric|min:0',
62
+      'nominativo' => 'nullable|string|max:255',
63
+      'email' => 'nullable|email|max:255',
64
+      'validita_da' => 'nullable|date',
65
+      'validita_a' => 'nullable|date|after_or_equal:validita_da',
66
+ 
67
+    ];
68
+  }
69
+
70
+  public function editMessages(): array{
71
+    return $this->messages;
72
+  }
73
+
74
+  /**
75
+  * Get remove action validation rules.
76
+  *
77
+  * @param Model $model
78
+  * @return array
79
+  */
80
+  public function removeRules(Model $model): array
81
+  {
82
+    return [];
83
+  }
84
+
85
+  public function creating(Model $model, array $data): array
86
+  {
87
+    $data['attivita_id'] = Session::get('attivita_attuale');
88
+    AttivitaService::garantisciAttivita($data['attivita_id']);
89
+    $data['stato'] = Cupon::GENERATO;
90
+    if(!isset($data['codice']) || empty($data['codice'])){
91
+      $data['codice'] = app('App\Http\Controllers\CuponController')->generaCodiceCupon();
92
+    }
93
+
94
+    return $data;
95
+  }
96
+
97
+  public function updating(Model $model, array $data): array
98
+  {
99
+    AttivitaService::garantisciAttivita($model->attivita_id);
100
+    unset($data['attivita_id']);
101
+
102
+    return $data;
103
+  }
104
+
105
+  public function deleting(Model $model, array $data): array
106
+  {
107
+    AttivitaService::garantisciAttivita($model->attivita_id);
108
+
109
+    return $data;
110
+  }
111
+  public function messages(): array
112
+  {
113
+    return $this->messages;
114
+  }
115
+
116
+
117
+}

+ 9
- 2
app/DataTables/DispositivoDataTable.php Просмотреть файл

@@ -16,6 +16,8 @@ use Illuminate\Support\Facades\Auth;
16 16
 
17 17
 class DispositivoDataTable extends DataTable
18 18
 {
19
+    public ?int $attivita_id = null;
20
+
19 21
     public function __construct()
20 22
     {
21 23
         $this->dataTableVariable = 'dataTable_dispositivo';
@@ -47,7 +49,12 @@ class DispositivoDataTable extends DataTable
47 49
      */
48 50
     public function query(Dispositivo $model): QueryBuilder
49 51
     {
50
-        return $model->newQuery();
52
+        $attivitaId = (int) $this->attivita_id;
53
+        if ($attivitaId <= 0) {
54
+            return $model->newQuery()->whereRaw('1 = 0');
55
+        }
56
+
57
+        return $model->newQuery()->where('attivita_id', $attivitaId);
51 58
     }
52 59
 
53 60
     /**
@@ -74,7 +81,7 @@ class DispositivoDataTable extends DataTable
74 81
                     ->editor(
75 82
                         Editor::make()
76 83
                             ->fields([
77
-                                Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
84
+                                Fields\Hidden::make('attivita_id')->label('Attività')->default((int) $this->attivita_id),
78 85
                                 Fields\Hidden::make('endpoint_id')->label('Endpoint ID'),
79 86
                                 Fields\Text::make('nome')->label('Nome'),
80 87
                                 Fields\Select2::make('tipo')->label('Tipo')->options(Dispositivo::getTipoDispositivo()->pluck('value', 'label')),

+ 15
- 12
app/DataTables/DispositivoDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 10
 
14 11
 class DispositivoDataTableEditor extends DataTablesEditor
15 12
 {
@@ -50,7 +47,6 @@ class DispositivoDataTableEditor extends DataTablesEditor
50 47
     return [
51 48
       'nome'  => 'required',
52 49
       'tipo' => 'required',
53
-      'attivita_id' => 'required|exists:attivita,id',
54 50
       'licenza' => 'nullable',
55 51
       'url_stampante' => 'nullable',
56 52
       'ubicazione' => 'nullable',
@@ -77,7 +73,6 @@ class DispositivoDataTableEditor extends DataTablesEditor
77 73
     return [
78 74
       'nome'  => 'required',
79 75
       'tipo' => 'required',
80
-      'attivita_id' => 'required|exists:attivita,id',
81 76
       'licenza' => 'nullable',
82 77
       'url_stampante' => 'nullable',
83 78
       'ubicazione' => 'nullable',
@@ -106,16 +101,24 @@ class DispositivoDataTableEditor extends DataTablesEditor
106 101
 
107 102
   public function creating(Model $model, array $data): array
108 103
   {
109
-    // $model->roles()->sync([$data['ruolo_id']]);
110
-    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
104
+    $data['attivita_id'] = Session::get('attivita_attuale');
105
+    AttivitaService::garantisciAttivita($data['attivita_id']);
106
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
111 107
     return $data;
112 108
   }
113 109
 
114 110
   public function updating(Model $model, array $data): array
115 111
   {
116
-    // dd($data['ruolo']);
117
-    // $model->roles()->sync([$data['ruolo_id']]);
118
-    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
112
+    AttivitaService::garantisciAttivita($model->attivita_id);
113
+    unset($data['attivita_id']);
114
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
115
+    return $data;
116
+  }
117
+
118
+  public function deleting(Model $model, array $data): array
119
+  {
120
+    AttivitaService::garantisciAttivita($model->attivita_id);
121
+
119 122
     return $data;
120 123
   }
121 124
   public function messages(): array

+ 24
- 3
app/DataTables/EndpointDataTableEditor.php Просмотреть файл

@@ -11,6 +11,8 @@ use Illuminate\Http\Request;
11 11
 use Illuminate\Validation\ValidationException;
12 12
 use Illuminate\Support\Facades\Storage;
13 13
 use Illuminate\Support\Str;
14
+use App\Services\Attivita\AttivitaService;
15
+use Illuminate\Support\Facades\Session;
14 16
 
15 17
 class EndpointDataTableEditor extends DataTablesEditor
16 18
 {
@@ -81,14 +83,33 @@ class EndpointDataTableEditor extends DataTablesEditor
81 83
 
82 84
   public function creating(Model $model, array $data): array
83 85
   {
84
-    // $model->roles()->sync([$data['ruolo_id']]);
86
+    $data = $this->senzaSegreti($data);
87
+    $data['attivita_id'] = Session::get('attivita_attuale');
88
+    AttivitaService::garantisciAttivita($data['attivita_id']);
89
+
85 90
     return $data;
86 91
   }
87 92
 
88 93
   public function updating(Model $model, array $data): array
89 94
   {
90
-    // dd($data['ruolo']);
91
-    // $model->roles()->sync([$data['ruolo_id']]);
95
+    AttivitaService::garantisciAttivita($model->attivita_id);
96
+    $data = $this->senzaSegreti($data);
97
+    unset($data['attivita_id']);
98
+
99
+    return $data;
100
+  }
101
+
102
+  public function deleting(Model $model, array $data): array
103
+  {
104
+    AttivitaService::garantisciAttivita($model->attivita_id);
105
+
106
+    return $data;
107
+  }
108
+
109
+  private function senzaSegreti(array $data): array
110
+  {
111
+    unset($data['token'], $data['product_key'], $data['secret'], $data['deeplink_token']);
112
+
92 113
     return $data;
93 114
   }
94 115
 

+ 68
- 44
app/DataTables/EventoDataTable.php Просмотреть файл

@@ -34,29 +34,38 @@ class EventoDataTable extends DataTable
34 34
             ->addColumn('stato_display', function($entity){
35 35
               return view('_partials.available', ['available' => $entity->is_attivo]);
36 36
             })
37
-            ->addColumn('data_inizio_display', function($entity){
38
-              return Carbon::parse($entity->data_inizio)->format('d/m/Y');
37
+            // ->addColumn('data_inizio_display', function($entity){
38
+            //   return Carbon::parse($entity->data_inizio)->format('d/m/Y');
39
+            // })
40
+            // ->addColumn('data_fine_display', function($entity){
41
+            //   return Carbon::parse($entity->data_fine)->format('d/m/Y');
42
+            // })
43
+            // ->addColumn('prezzo_display', function($entity){
44
+            //   return '€ ' . number_format($entity->prezzo, 2, ',', '.');
45
+            // })
46
+            // ->addColumn('apertura_prenotazione_display', function($entity){
47
+            //   return Carbon::parse($entity->apertura_prenotazione)->format('d/m/Y H:i');
48
+            // })
49
+            // ->addColumn('chiusura_prenotazione_display', function($entity){
50
+            //   return Carbon::parse($entity->chiusura_prenotazione)->format('d/m/Y H:i');
51
+            // })
52
+            // ->addColumn('periodo_evento_display', function($entity){
53
+            //   return Carbon::parse($entity->data_inizio)->format('d/m/Y') . ' - ' . Carbon::parse($entity->data_fine)->format('d/m/Y');
54
+            // })
55
+            // ->addColumn('periodo_prenotazioni_display', function($entity){
56
+            //   return Carbon::parse($entity->apertura_prenotazione)->format('d/m/Y') . ' - ' . Carbon::parse($entity->chiusura_prenotazione)->format('d/m/Y');
57
+            // })
58
+            // ->addColumn('prezzo_fisso_display', function($entity){
59
+            //   return view('_partials.available', ['available' => $entity->prezzo_fisso]);
60
+            // })
61
+            ->addColumn('posti_prenotati_confermati', function($entity){
62
+              return $entity->getCopertiConfermati();
39 63
             })
40
-            ->addColumn('data_fine_display', function($entity){
41
-              return Carbon::parse($entity->data_fine)->format('d/m/Y');
64
+            ->addColumn('posti_prenotati_non_confermati', function($entity){
65
+              return $entity->getPostiNonConfermati();
42 66
             })
43
-            ->addColumn('prezzo_display', function($entity){
44
-              return '€ ' . number_format($entity->prezzo, 2, ',', '.');
45
-            })
46
-            ->addColumn('apertura_prenotazione_display', function($entity){
47
-              return Carbon::parse($entity->apertura_prenotazione)->format('d/m/Y H:i');
48
-            })
49
-            ->addColumn('chiusura_prenotazione_display', function($entity){
50
-              return Carbon::parse($entity->chiusura_prenotazione)->format('d/m/Y H:i');
51
-            })
52
-            ->addColumn('periodo_evento_display', function($entity){
53
-              return Carbon::parse($entity->data_inizio)->format('d/m/Y') . ' - ' . Carbon::parse($entity->data_fine)->format('d/m/Y');
54
-            })
55
-            ->addColumn('periodo_prenotazioni_display', function($entity){
56
-              return Carbon::parse($entity->apertura_prenotazione)->format('d/m/Y') . ' - ' . Carbon::parse($entity->chiusura_prenotazione)->format('d/m/Y');
57
-            })
58
-            ->addColumn('prezzo_fisso_display', function($entity){
59
-              return view('_partials.available', ['available' => $entity->prezzo_fisso]);
67
+            ->addColumn('posti_rimasti', function($entity){
68
+              return $entity->posti - $entity->getCopertiConfermati() - $entity->getPostiNonConfermati();
60 69
             })
61 70
             ->setRowId('id');
62 71
     }
@@ -68,7 +77,12 @@ class EventoDataTable extends DataTable
68 77
      */
69 78
     public function query(Evento $model): QueryBuilder
70 79
     {
71
-        return $model->newQuery();
80
+        $attivitaId = (int) $this->attivita_id;
81
+        if ($attivitaId <= 0) {
82
+            return $model->newQuery()->whereRaw('1 = 0');
83
+        }
84
+
85
+        return $model->newQuery()->where('attivita_id', $attivitaId);
72 86
     }
73 87
 
74 88
     /**
@@ -78,19 +92,25 @@ class EventoDataTable extends DataTable
78 92
     {
79 93
         $buttons = [];
80 94
         if(Auth::user()->can('create-evento')){
81
-            array_push($buttons, Button::make('create')
82
-                ->editor('editor')
95
+
96
+            // array_push($buttons, Button::make('create')
97
+            //     ->editor('editor')
98
+            //     ->className('btn btn-sm btn-primary mb-4')
99
+            //     ->formTitle('Crea nuovo evento')
100
+            //     ->formButtons([
101
+            //         Button::raw('Annulla')
102
+            //             ->className('btn btn-secondary ml-2')
103
+            //             ->actionClose(),
104
+            //         Button::raw('Salva')
105
+            //             ->className('btn btn-success ml-2')
106
+            //             ->actionHandler('create')
107
+            //     ])
108
+            //     ->text('<i class="fas fa-plus"></i> Nuovo evento'));
109
+
110
+            array_push($buttons, Button::raw('nuovoEvento')
83 111
                 ->className('btn btn-sm btn-primary mb-4')
84
-                ->formTitle('Crea nuovo evento')
85
-                ->formButtons([
86
-                    Button::raw('Annulla')
87
-                        ->className('btn btn-secondary ml-2')
88
-                        ->actionClose(),
89
-                    Button::raw('Salva')
90
-                        ->className('btn btn-success ml-2')
91
-                        ->actionHandler('create')
92
-                ])
93
-                ->text('<i class="fas fa-plus"></i> Nuovo evento'));
112
+                ->text('<i class="fas fa-plus"></i> Nuovo evento')
113
+                ->action("nuovoEvento()"));
94 114
         }
95 115
         return $this->builder()
96 116
                     ->setTableId($this->dataTableVariable)
@@ -135,17 +155,21 @@ class EventoDataTable extends DataTable
135 155
         return [
136 156
             Column::make('id')->title('ID')->width('10%')->visible(false),
137 157
             Column::make('stato')->data('stato_display')->title('Stato')->addClass('text-center')->responsivePriority(1)->width('10%'),
138
-            Column::make('nome')->title('Nome')->responsivePriority(1),
158
+            Column::make('nome')->title('Titolo')->responsivePriority(1),
159
+            Column::make('posti')->title('Posti')->responsivePriority(2),
160
+            Column::computed('posti_prenotati_non_confermati')->title('NON confermati')->responsivePriority(2)->addClass('text-center text-warning'),
161
+            Column::computed('posti_prenotati_confermati')->title('Confermati')->responsivePriority(2)->addClass('text-center text-success'),
162
+            Column::computed('posti_rimasti')->title('Rimasti')->responsivePriority(2)->addClass('text-center'),
139 163
             // Column::make('descrizione')->title('Descrizione'),
140
-            Column::computed('periodo_evento_display')->title('Periodo evento')->responsivePriority(2),
141
-            Column::computed('periodo_prenotazioni_display')->title('Periodo prenotazioni')->responsivePriority(2),
142
-            Column::make('data_inizio')->title('Data inizio')->data('data_inizio_display')->visible(false)->responsivePriority(2),
143
-            Column::make('data_fine')->title('Data fine')->data('data_fine_display')->visible(false)->responsivePriority(2),
144
-            Column::make('apertura_prenotazione')->title('Apertura prenotazione')->data('apertura_prenotazione_display')->visible(false)->responsivePriority(2),
145
-            Column::make('chiusura_prenotazione')->title('Chiusura prenotazione')->data('chiusura_prenotazione_display')->visible(false)->responsivePriority(2),
146
-            Column::make('prezzo_fisso')->title('Prezzo fisso')->data('prezzo_fisso_display')->addClass('text-center')->responsivePriority(2),
147
-            Column::make('prezzo')->title('Prezzo')->data('prezzo_display')->addClass('text-center')->responsivePriority(2),
148
-            Column::make('note')->title('Note')->visible(false)->responsivePriority(2),
164
+            // Column::computed('periodo_evento_display')->title('Periodo evento')->responsivePriority(2),
165
+            // Column::computed('periodo_prenotazioni_display')->title('Periodo prenotazioni')->responsivePriority(2),
166
+            // Column::make('data_inizio')->title('Data inizio')->data('data_inizio_display')->visible(false)->responsivePriority(2),
167
+            // Column::make('data_fine')->title('Data fine')->data('data_fine_display')->visible(false)->responsivePriority(2),
168
+            // Column::make('apertura_prenotazione')->title('Apertura prenotazione')->data('apertura_prenotazione_display')->visible(false)->responsivePriority(2),
169
+            // Column::make('chiusura_prenotazione')->title('Chiusura prenotazione')->data('chiusura_prenotazione_display')->visible(false)->responsivePriority(2),
170
+            // Column::make('prezzo_fisso')->title('Prezzo fisso')->data('prezzo_fisso_display')->addClass('text-center')->responsivePriority(2),
171
+            // Column::make('prezzo')->title('Prezzo')->data('prezzo_display')->addClass('text-center')->responsivePriority(2),
172
+            // Column::make('note')->title('Note')->visible(false)->responsivePriority(2),
149 173
             Column::computed('action')
150 174
                   ->title('')
151 175
                   ->exportable(false)

+ 24
- 4
app/DataTables/EventoDataTableEditor.php Просмотреть файл

@@ -3,12 +3,14 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Evento;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7 8
 use Illuminate\Http\JsonResponse;
8 9
 use Illuminate\Http\UploadedFile;
9 10
 use Yajra\DataTables\DataTablesEditor;
10 11
 use Illuminate\Http\Request;
11 12
 use Illuminate\Validation\ValidationException;
13
+use Illuminate\Support\Facades\Session;
12 14
 use Illuminate\Support\Facades\Storage;
13 15
 use Illuminate\Support\Str;
14 16
 
@@ -110,14 +112,24 @@ class EventoDataTableEditor extends DataTablesEditor
110 112
 
111 113
   public function creating(Model $model, array $data): array
112 114
   {
113
-    // $model->roles()->sync([$data['ruolo_id']]);
115
+    $data['attivita_id'] = Session::get('attivita_attuale');
116
+    AttivitaService::garantisciAttivita($data['attivita_id']);
117
+
114 118
     return $data;
115 119
   }
116 120
 
117 121
   public function updating(Model $model, array $data): array
118 122
   {
119
-    // dd($data['ruolo']);
120
-    // $model->roles()->sync([$data['ruolo_id']]);
123
+    AttivitaService::garantisciAttivita($model->attivita_id);
124
+    unset($data['attivita_id']);
125
+
126
+    return $data;
127
+  }
128
+
129
+  public function deleting(Model $model, array $data): array
130
+  {
131
+    AttivitaService::garantisciAttivita($model->attivita_id);
132
+
121 133
     return $data;
122 134
   }
123 135
 
@@ -246,10 +258,18 @@ class EventoDataTableEditor extends DataTablesEditor
246 258
   {
247 259
     $id = $request->input('id');
248 260
     if ($id !== null && $id !== '' && is_numeric($id)) {
261
+      $evento = Evento::find((int) $id);
262
+      if (! $evento) {
263
+        abort(404);
264
+      }
265
+      AttivitaService::garantisciAttivita($evento->attivita_id);
266
+
249 267
       return $this->uploadDir.'/'.(int) $id;
250 268
     }
251 269
 
252
-    return $this->uploadDir; //$this->uploadDir.'/tmp';
270
+    AttivitaService::garantisciAttivita(Session::get('attivita_attuale'));
271
+
272
+    return $this->uploadDir;
253 273
   }
254 274
 
255 275
   protected function getUploadedFilename(string $field, UploadedFile $uploadedFile): string

+ 17
- 9
app/DataTables/EventoFormDataTableEditor.php Просмотреть файл

@@ -2,14 +2,11 @@
2 2
 
3 3
 namespace App\DataTables;
4 4
 
5
+use App\Models\Evento;
5 6
 use App\Models\EventoForm;
7
+use App\Services\Attivita\AttivitaService;
6 8
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 10
 
14 11
 class EventoFormDataTableEditor extends DataTablesEditor
15 12
 {
@@ -94,17 +91,28 @@ class EventoFormDataTableEditor extends DataTablesEditor
94 91
   public function creating(Model $model, array $data): array
95 92
   {
96 93
     $eventoId = request()->query('evento_id') ?? request()->input('evento_id');
97
-    if ($eventoId) {
98
-      $data['evento_id'] = (int) $eventoId;
94
+    $evento = Evento::find($eventoId);
95
+    if (! $evento) {
96
+      abort(404);
99 97
     }
98
+    AttivitaService::garantisciEventoDiQuestaAttivita($evento);
99
+    $data['evento_id'] = (int) $evento->id;
100 100
 
101 101
     return $data;
102 102
   }
103 103
 
104 104
   public function updating(Model $model, array $data): array
105 105
   {
106
-    // dd($data['ruolo']);
107
-    // $model->roles()->sync([$data['ruolo_id']]);
106
+    AttivitaService::garantisciEventoDiQuestaAttivita($model->evento);
107
+    unset($data['evento_id']);
108
+
109
+    return $data;
110
+  }
111
+
112
+  public function deleting(Model $model, array $data): array
113
+  {
114
+    AttivitaService::garantisciEventoDiQuestaAttivita($model->evento);
115
+
108 116
     return $data;
109 117
   }
110 118
   public function messages(): array

+ 5
- 1
app/DataTables/FatturaDataTable.php Просмотреть файл

@@ -52,7 +52,11 @@ class FatturaDataTable extends DataTable
52 52
      */
53 53
     public function query(Fattura $model): QueryBuilder
54 54
     {
55
-        return $model->newQuery();
55
+        if (Auth::user()?->hasRole('superadmin')) {
56
+            return $model->newQuery();
57
+        }
58
+
59
+        return $model->newQuery()->where('user_id', Auth::id());
56 60
     }
57 61
 
58 62
     /**

+ 15
- 8
app/DataTables/FatturaDataTableEditor.php Просмотреть файл

@@ -4,12 +4,8 @@ namespace App\DataTables;
4 4
 
5 5
 use App\Models\Fattura;
6 6
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
7
+use Illuminate\Support\Facades\Auth;
8 8
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 9
 
14 10
 class FatturaDataTableEditor extends DataTablesEditor
15 11
 {
@@ -90,14 +86,25 @@ class FatturaDataTableEditor extends DataTablesEditor
90 86
 
91 87
   public function creating(Model $model, array $data): array
92 88
   {
93
-    // $model->roles()->sync([$data['ruolo_id']]);
89
+    $data['user_id'] = Auth::id();
94 90
     return $data;
95 91
   }
96 92
 
97 93
   public function updating(Model $model, array $data): array
98 94
   {
99
-    // dd($data['ruolo']);
100
-    // $model->roles()->sync([$data['ruolo_id']]);
95
+    if (! Auth::user()?->hasRole('superadmin') && (int) $model->user_id !== (int) Auth::id()) {
96
+      abort(404);
97
+    }
98
+    unset($data['user_id']);
99
+    return $data;
100
+  }
101
+
102
+  public function deleting(Model $model, array $data): array
103
+  {
104
+    if (! Auth::user()?->hasRole('superadmin') && (int) $model->user_id !== (int) Auth::id()) {
105
+      abort(404);
106
+    }
107
+
101 108
     return $data;
102 109
   }
103 110
   public function messages(): array

+ 13
- 8
app/DataTables/FornitoreDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Fornitore;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 10
 
14 11
 class FornitoreDataTableEditor extends DataTablesEditor
15 12
 {
@@ -88,14 +85,22 @@ class FornitoreDataTableEditor extends DataTablesEditor
88 85
 
89 86
   public function creating(Model $model, array $data): array
90 87
   {
91
-    // $model->roles()->sync([$data['ruolo_id']]);
88
+    $data['attivita_id'] = Session::get('attivita_attuale');
89
+    AttivitaService::garantisciAttivita($data['attivita_id']);
92 90
     return $data;
93 91
   }
94 92
 
95 93
   public function updating(Model $model, array $data): array
96 94
   {
97
-    // dd($data['ruolo']);
98
-    // $model->roles()->sync([$data['ruolo_id']]);
95
+    AttivitaService::garantisciAttivita($model->attivita_id);
96
+    unset($data['attivita_id']);
97
+    return $data;
98
+  }
99
+
100
+  public function deleting(Model $model, array $data): array
101
+  {
102
+    AttivitaService::garantisciAttivita($model->attivita_id);
103
+
99 104
     return $data;
100 105
   }
101 106
   public function messages(): array

+ 13
- 9
app/DataTables/ImpostazioniDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Impostazioni;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 10
 
14 11
 class ImpostazioniDataTableEditor extends DataTablesEditor
15 12
 {
@@ -114,15 +111,22 @@ class ImpostazioniDataTableEditor extends DataTablesEditor
114 111
 
115 112
   public function creating(Model $model, array $data): array
116 113
   {
117
-    // $model->roles()->sync([$data['ruolo_id']]);
114
+    $data['attivita_id'] = Session::get('attivita_attuale');
115
+    AttivitaService::garantisciAttivita($data['attivita_id']);
118 116
     return $data;
119 117
   }
120 118
 
121 119
   public function updating(Model $model, array $data): array
122 120
   {
123
-    // $data['valore'] = $data['valore'] == 'true' ? true : false;
124
-    // dd($data['ruolo']);
125
-    // $model->roles()->sync([$data['ruolo_id']]);
121
+    AttivitaService::garantisciAttivita($model->attivita_id);
122
+    unset($data['attivita_id']);
123
+    return $data;
124
+  }
125
+
126
+  public function deleting(Model $model, array $data): array
127
+  {
128
+    AttivitaService::garantisciAttivita($model->attivita_id);
129
+
126 130
     return $data;
127 131
   }
128 132
   public function messages(): array

+ 7
- 4
app/DataTables/MetodoPagamentoDataTable.php Просмотреть файл

@@ -17,6 +17,8 @@ use App\Models\Attivita;
17 17
 
18 18
 class MetodoPagamentoDataTable extends DataTable
19 19
 {
20
+    public ?int $attivita_id = null;
21
+
20 22
     public function __construct()
21 23
     {
22 24
         $this->dataTableVariable = 'dataTable_metodo_pagamento';
@@ -55,11 +57,12 @@ class MetodoPagamentoDataTable extends DataTable
55 57
      */
56 58
     public function query(MetodoPagamento $model): QueryBuilder
57 59
     {
58
-        if($this->attivita_id){
59
-            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('nome', 'asc');
60
-        }else{
60
+        $attivitaId = (int) $this->attivita_id;
61
+        if ($attivitaId <= 0) {
61 62
             return $model->newQuery()->whereRaw('1 = 0');
62 63
         }
64
+
65
+        return $model->newQuery()->where('attivita_id', $attivitaId)->orderBy('nome', 'asc');
63 66
     }
64 67
 
65 68
     /**
@@ -88,7 +91,7 @@ class MetodoPagamentoDataTable extends DataTable
88 91
                     ->editor(
89 92
                         Editor::make()
90 93
                             ->fields([
91
-                                Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
94
+                                Fields\Hidden::make('attivita_id')->label('Attività')->default((int) $this->attivita_id),
92 95
                                 Fields\Boolean::make('is_attivo')->label('Attivo')->default(true),
93 96
                                 Fields\Select2::make('tipo')->label('Tipo')->options(MetodoPagamento::getTipiPagamento()->sortBy('label')->pluck('value' ,'label')),
94 97
                                 Fields\Text::make('nome')->label('Nome'),

+ 13
- 9
app/DataTables/MetodoPagamentoDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\MetodoPagamento;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8 8
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
9
+use Illuminate\Support\Facades\Session;
13 10
 
14 11
 class  MetodoPagamentoDataTableEditor extends DataTablesEditor
15 12
 {
@@ -58,7 +55,6 @@ class  MetodoPagamentoDataTableEditor extends DataTablesEditor
58 55
     return [
59 56
       'nome'  => 'required',
60 57
       'tipo' => 'required|in:'.MetodoPagamento::getTipiPagamento()->pluck('value')->implode(','),
61
-      'attivita_id' => 'required|exists:attivita,id',
62 58
       // 'is_attivo' => 'boolean',
63 59
       // 'is_pubblico' => 'boolean',
64 60
       'key' => 'nullable',
@@ -85,7 +81,8 @@ class  MetodoPagamentoDataTableEditor extends DataTablesEditor
85 81
 
86 82
   public function creating(Model $model, array $data): array
87 83
   {
88
-    // $model->roles()->sync([$data['ruolo_id']]);
84
+    $data['attivita_id'] = Session::get('attivita_attuale');
85
+    AttivitaService::garantisciAttivita($data['attivita_id']);
89 86
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
90 87
     $data['is_pubblico'] = isset($data['is_pubblico']) ? true : false;
91 88
     return $data;
@@ -93,13 +90,20 @@ class  MetodoPagamentoDataTableEditor extends DataTablesEditor
93 90
 
94 91
   public function updating(Model $model, array $data): array
95 92
   {
96
-    // dd($data['ruolo']);
97
-    // $model->roles()->sync([$data['ruolo_id']]);
93
+    AttivitaService::garantisciAttivita($model->attivita_id);
94
+    unset($data['attivita_id']);
98 95
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
99 96
     $data['is_pubblico'] = isset($data['is_pubblico']) ? true : false;
100 97
     return $data;
101 98
   }
102 99
 
100
+  public function deleting(Model $model, array $data): array
101
+  {
102
+    AttivitaService::garantisciAttivita($model->attivita_id);
103
+
104
+    return $data;
105
+  }
106
+
103 107
   public function messages(): array
104 108
   {
105 109
     return $this->messages;

+ 17
- 12
app/DataTables/MonitorDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 10
 
14 11
 class MonitorDataTableEditor extends DataTablesEditor
15 12
 {
@@ -50,7 +47,6 @@ class MonitorDataTableEditor extends DataTablesEditor
50 47
     return [
51 48
       'nome'  => 'required',
52 49
       'tipo' => 'required|in:'.Dispositivo::MONITOR,
53
-      'attivita_id' => 'required|exists:attivita,id',
54 50
       'licenza' => 'nullable',
55 51
       'url_stampante' => 'nullable',
56 52
       'ubicazione' => 'nullable',
@@ -77,7 +73,6 @@ class MonitorDataTableEditor extends DataTablesEditor
77 73
     return [
78 74
       'nome'  => 'required',
79 75
       'tipo' => 'required|in:'.Dispositivo::MONITOR,
80
-      'attivita_id' => 'required|exists:attivita,id',
81 76
       'licenza' => 'nullable',
82 77
       'url_stampante' => 'nullable',
83 78
       'ubicazione' => 'nullable',
@@ -106,16 +101,26 @@ class MonitorDataTableEditor extends DataTablesEditor
106 101
 
107 102
   public function creating(Model $model, array $data): array
108 103
   {
109
-    // $model->roles()->sync([$data['ruolo_id']]);
110
-    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
104
+    $data['attivita_id'] = Session::get('attivita_attuale');
105
+    AttivitaService::garantisciAttivita($data['attivita_id']);
106
+    $data['tipo'] = Dispositivo::MONITOR;
107
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
111 108
     return $data;
112 109
   }
113 110
 
114 111
   public function updating(Model $model, array $data): array
115 112
   {
116
-    // dd($data['ruolo']);
117
-    // $model->roles()->sync([$data['ruolo_id']]);
118
-    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
113
+    AttivitaService::garantisciAttivita($model->attivita_id);
114
+    unset($data['attivita_id']);
115
+    $data['tipo'] = Dispositivo::MONITOR;
116
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
117
+    return $data;
118
+  }
119
+
120
+  public function deleting(Model $model, array $data): array
121
+  {
122
+    AttivitaService::garantisciAttivita($model->attivita_id);
123
+
119 124
     return $data;
120 125
   }
121 126
   public function messages(): array

+ 2
- 0
app/DataTables/OperatoreDataTable.php Просмотреть файл

@@ -15,6 +15,8 @@ use Illuminate\Support\Facades\Auth;
15 15
 
16 16
 class OperatoreDataTable extends DataTable
17 17
 {
18
+    public ?int $attivita_id = null;
19
+
18 20
     public function __construct()
19 21
     {
20 22
         $this->dataTableVariable = 'dataTable_operatore';

+ 14
- 9
app/DataTables/OperatoreDataTableEditor.php Просмотреть файл

@@ -3,14 +3,11 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Operatore;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
-use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
8
+use Illuminate\Support\Facades\Session;
12 9
 use Illuminate\Support\Str;
13
-use Illuminate\Support\Facades\Hash;
10
+use Yajra\DataTables\DataTablesEditor;
14 11
 
15 12
 class OperatoreDataTableEditor extends DataTablesEditor
16 13
 {
@@ -84,7 +81,8 @@ class OperatoreDataTableEditor extends DataTablesEditor
84 81
 
85 82
   public function creating(Model $model, array $data): array
86 83
   {
87
-    // $model->roles()->sync([$data['ruolo_id']]);
84
+    $data['attivita_id'] = Session::get('attivita_attuale');
85
+    AttivitaService::garantisciAttivita($data['attivita_id']);
88 86
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
89 87
     if(!isset($data['password'])){
90 88
       $data['password'] = Str::random(8);
@@ -95,12 +93,19 @@ class OperatoreDataTableEditor extends DataTablesEditor
95 93
 
96 94
   public function updating(Model $model, array $data): array
97 95
   {
98
-    // dd($data['ruolo']);
99
-    // $model->roles()->sync([$data['ruolo_id']]);
96
+    AttivitaService::garantisciAttivita($model->attivita_id);
97
+    unset($data['attivita_id']);
100 98
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
101 99
     $data['username'] = $this->createUsername($data);
102 100
     return $data;
103 101
   }
102
+
103
+  public function deleting(Model $model, array $data): array
104
+  {
105
+    AttivitaService::garantisciAttivita($model->attivita_id);
106
+
107
+    return $data;
108
+  }
104 109
   public function messages(): array
105 110
   {
106 111
     return $this->messages;

+ 32
- 4
app/DataTables/OpzioneFormDataTableEditor.php Просмотреть файл

@@ -2,7 +2,9 @@
2 2
 
3 3
 namespace App\DataTables;
4 4
 
5
+use App\Models\EventoForm;
5 6
 use App\Models\OpzioneForm;
7
+use App\Services\Attivita\AttivitaService;
6 8
 use Illuminate\Database\Eloquent\Model;
7 9
 use Yajra\DataTables\DataTablesEditor;
8 10
 
@@ -40,11 +42,37 @@ class OpzioneFormDataTableEditor extends DataTablesEditor
40 42
 
41 43
     public function creating(Model $model, array $data): array
42 44
     {
43
-        $efId = request()->query('evento_form_id') ?? request()->input('evento_form_id');
44
-        if ($efId) {
45
-            $data['evento_form_id'] = (int) $efId;
46
-        }
45
+        $form = $this->garantisciFormDiQuestaAttivita(
46
+            request()->query('evento_form_id') ?? request()->input('evento_form_id') ?? ($data['evento_form_id'] ?? null)
47
+        );
48
+        $data['evento_form_id'] = (int) $form->id;
49
+
50
+        return $data;
51
+    }
52
+
53
+    public function updating(Model $model, array $data): array
54
+    {
55
+        $this->garantisciFormDiQuestaAttivita($model->evento_form_id);
56
+        unset($data['evento_form_id']);
57
+
58
+        return $data;
59
+    }
60
+
61
+    public function deleting(Model $model, array $data): array
62
+    {
63
+        $this->garantisciFormDiQuestaAttivita($model->evento_form_id);
47 64
 
48 65
         return $data;
49 66
     }
67
+
68
+    private function garantisciFormDiQuestaAttivita($formId): EventoForm
69
+    {
70
+        $form = EventoForm::find($formId);
71
+        if (! $form) {
72
+            abort(404);
73
+        }
74
+        AttivitaService::garantisciEventoDiQuestaAttivita($form->evento);
75
+
76
+        return $form;
77
+    }
50 78
 }

+ 30
- 8
app/DataTables/OrdineDataTableEditor.php Просмотреть файл

@@ -3,13 +3,11 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Ordine;
6
+use App\Models\Prenotazione;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8 8
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
9
+use App\Services\Attivita\AttivitaService;
10
+use Illuminate\Support\Facades\Session;
13 11
 
14 12
 class OrdineDataTableEditor extends DataTablesEditor
15 13
 {
@@ -91,16 +89,40 @@ class OrdineDataTableEditor extends DataTablesEditor
91 89
 
92 90
   public function creating(Model $model, array $data): array
93 91
   {
94
-    // $model->roles()->sync([$data['ruolo_id']]);
92
+    $data['attivita_id'] = Session::get('attivita_attuale');
93
+    AttivitaService::garantisciAttivita($data['attivita_id']);
94
+    $this->garantisciPrenotazioneDiQuestaAttivita($data['prenotazione_id'] ?? null, $data['attivita_id']);
95
+
95 96
     return $data;
96 97
   }
97 98
 
98 99
   public function updating(Model $model, array $data): array
99 100
   {
100
-    // dd($data['ruolo']);
101
-    // $model->roles()->sync([$data['ruolo_id']]);
101
+    AttivitaService::garantisciAttivita($model->attivita_id);
102
+    unset($data['attivita_id']);
103
+    $this->garantisciPrenotazioneDiQuestaAttivita($data['prenotazione_id'] ?? $model->prenotazione_id, $model->attivita_id);
104
+
102 105
     return $data;
103 106
   }
107
+
108
+  public function deleting(Model $model, array $data): array
109
+  {
110
+    AttivitaService::garantisciAttivita($model->attivita_id);
111
+
112
+    return $data;
113
+  }
114
+
115
+  private function garantisciPrenotazioneDiQuestaAttivita($prenotazioneId, $attivitaId): void
116
+  {
117
+    if (! $prenotazioneId) {
118
+      return;
119
+    }
120
+
121
+    $prenotazione = Prenotazione::with('evento')->find($prenotazioneId);
122
+    if (! $prenotazione || (int) $prenotazione->evento?->attivita_id !== (int) $attivitaId) {
123
+      abort(404);
124
+    }
125
+  }
104 126
   public function messages(): array
105 127
   {
106 128
     return $this->messages;

+ 11
- 12
app/DataTables/PagamentoDataTable.php Просмотреть файл

@@ -3,10 +3,7 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Pagamento;
6
-use App\Models\Ordine;
7
-use App\Models\Prenotazione;
8 6
 use App\Models\MetodoPagamento;
9
-use App\Models\Attivita;
10 7
 use Illuminate\Database\Eloquent\Builder as QueryBuilder;
11 8
 use Yajra\DataTables\EloquentDataTable;
12 9
 use Yajra\DataTables\Html\Builder as HtmlBuilder;
@@ -64,11 +61,12 @@ class PagamentoDataTable extends DataTable
64 61
      */
65 62
     public function query(Pagamento $model): QueryBuilder
66 63
     {
67
-        if($this->attivita_id){
68
-            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('created_at', 'desc');
69
-        }else{
64
+        $attivitaId = (int) $this->attivita_id;
65
+        if ($attivitaId <= 0) {
70 66
             return $model->newQuery()->whereRaw('1 = 0')->orderBy('created_at', 'desc');
71 67
         }
68
+
69
+        return $model->newQuery()->where('attivita_id', $attivitaId)->orderBy('created_at', 'desc');
72 70
     }
73 71
 
74 72
     /**
@@ -98,15 +96,15 @@ class PagamentoDataTable extends DataTable
98 96
                     ->editor(
99 97
                         Editor::make()
100 98
                             ->fields([
101
-                                Fields\Text::make('attivita_id')->label('Attività')->options(Attivita::all()->pluck('nome', 'id')),
102
-                                Fields\Select2::make('ordine_id')->label('Ordine')->options(Ordine::all()->pluck('id', 'nome')),
103
-                                Fields\Select2::make('prenotazione_id')->label('Prenotazione')->options(Prenotazione::all()->pluck('id', 'nome')),
99
+                                Fields\Hidden::make('attivita_id')->default((int) $this->attivita_id),
100
+                                Fields\Hidden::make('ordine_id'),
101
+                                Fields\Hidden::make('prenotazione_id'),
104 102
                                 Fields\Text::make('importo')->label('Importo'),
105 103
                                 Fields\Text::make('causale')->label('Causale'),
106 104
                                 Fields\Select2::make('stato')->label('Stato')->options(Pagamento::getStati()->pluck('value', 'label')),
107
-                                Fields\Select2::make('metodo_pagamento_id')->label('Metodo pagamento')->options(MetodoPagamento::all()->pluck('id', 'nome')),
105
+                                Fields\Select2::make('metodo_pagamento_id')->label('Metodo pagamento')->options(MetodoPagamento::where('attivita_id', (int) $this->attivita_id)->where('is_attivo', true)->pluck('id' , 'nome')),
108 106
                                 Fields\Text::make('note')->label('Note'),
109
-                                Fields\Text::make('info')->label('Info'),
107
+                                // Fields\Text::make('info')->label('Info'),
110 108
                             ])
111 109
                     )
112 110
                     ->initComplete("function(settings, json){
@@ -127,7 +125,8 @@ class PagamentoDataTable extends DataTable
127 125
             Column::make('prenotazione_id')->title('Prenotazione')->data('prenotazione_id_display'),
128 126
             Column::make('importo')->title('Importo')->data('importo_display'),
129 127
             Column::make('causale')->title('Causale'),
130
-            Column::make('metodo_pagamento_id')->title('Metodo pagamento')->data('metodo_pagamento_id_display'),
128
+            Column::make('metodo_pagamento_id')->visible(false)->width('10%'),
129
+            Column::make('metodo_pagamento_id_display')->title('Metodo pagamento')->data('metodo_pagamento_id_display'),
131 130
             Column::make('note')->title('Note'),
132 131
             Column::computed('action')
133 132
                   ->title('')

+ 141
- 0
app/DataTables/PagamentoDataTableEditor.php Просмотреть файл

@@ -0,0 +1,141 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\Ordine;
6
+use App\Models\Pagamento;
7
+use App\Models\Prenotazione;
8
+use App\Models\MetodoPagamento;
9
+use App\Services\Attivita\AttivitaService;
10
+use Illuminate\Database\Eloquent\Model;
11
+use Yajra\DataTables\DataTablesEditor;
12
+use Illuminate\Support\Facades\Session;
13
+
14
+class PagamentoDataTableEditor extends DataTablesEditor
15
+{
16
+  protected $model = Pagamento::class;
17
+
18
+  protected $messages = [
19
+    'attivita_id.required' => 'L\'attività è richiesta',
20
+    'ordine_id.required' => 'L\'ordine è richiesto',
21
+    'prenotazione_id.required' => 'La prenotazione è richiesta',
22
+    'importo.required' => 'L\'importo è richiesto',
23
+    'causale.required' => 'La causale è richiesta',
24
+    'stato.required' => 'Lo stato è richiesto',
25
+    'metodo_pagamento_id.required' => 'Il metodo di pagamento è richiesto',
26
+    'note.required' => 'La note è richiesta',
27
+    'info.required' => 'L\'info è richiesta',
28
+  ];
29
+
30
+  /**
31
+  * Get create action validation rules.
32
+  *
33
+  * @return array
34
+  */
35
+  public function createRules(): array
36
+  {
37
+    return [
38
+      'ordine_id' => 'required|exists:ordine,id',
39
+      'prenotazione_id' => 'nullable|exists:prenotazione,id',
40
+      'importo' => 'required|numeric',
41
+      'causale' => 'required|string',
42
+      'stato' => 'required|string',
43
+      'metodo_pagamento_id' => 'required|exists:metodo_pagamento,id',
44
+      'note' => 'nullable',
45
+      'info' => 'nullable',
46
+    ];
47
+  }
48
+
49
+  public function createMessages(): array{
50
+    return $this->messages;
51
+  }
52
+
53
+  /**
54
+  * Get edit action validation rules.
55
+  *
56
+  * @param Model $model
57
+  * @return array
58
+  */
59
+  public function editRules(Model $model): array
60
+  {
61
+    return [
62
+      'ordine_id' => 'required|exists:ordine,id',
63
+      'prenotazione_id' => 'nullable|exists:prenotazione,id',
64
+      'importo' => 'required|numeric',
65
+      'causale' => 'required|string',
66
+      'stato' => 'required|string',
67
+      'metodo_pagamento_id' => 'required|exists:metodo_pagamento,id',
68
+      'note' => 'nullable',
69
+      'info' => 'nullable',
70
+    ];
71
+  }
72
+
73
+  public function editMessages(): array{
74
+    return $this->messages;
75
+  }
76
+
77
+  /**
78
+  * Get remove action validation rules.
79
+  *
80
+  * @param Model $model
81
+  * @return array
82
+  */
83
+  public function removeRules(Model $model): array
84
+  {
85
+    return [];
86
+  }
87
+
88
+  public function creating(Model $model, array $data): array
89
+  {
90
+    $data['attivita_id'] = Session::get('attivita_attuale');
91
+    AttivitaService::garantisciAttivita($data['attivita_id']);
92
+    $this->garantisciRelazioniDiQuestaAttivita($data, $data['attivita_id']);
93
+
94
+    return $data;
95
+  }
96
+
97
+  public function updating(Model $model, array $data): array
98
+  {
99
+    AttivitaService::garantisciAttivita($model->attivita_id);
100
+    unset($data['attivita_id']);
101
+    $this->garantisciRelazioniDiQuestaAttivita($data, $model->attivita_id, $model);
102
+
103
+    return $data;
104
+  }
105
+
106
+  public function deleting(Model $model, array $data): array
107
+  {
108
+    AttivitaService::garantisciAttivita($model->attivita_id);
109
+
110
+    return $data;
111
+  }
112
+
113
+  public function messages(): array
114
+  {
115
+    return $this->messages;
116
+  }
117
+
118
+  private function garantisciRelazioniDiQuestaAttivita(array $data, $attivitaId, ?Model $model = null): void
119
+  {
120
+    $ordineId = $data['ordine_id'] ?? $model?->ordine_id;
121
+    $ordine = Ordine::find($ordineId);
122
+    if (! $ordine || (int) $ordine->attivita_id !== (int) $attivitaId) {
123
+      abort(404);
124
+    }
125
+
126
+    $prenotazioneId = $data['prenotazione_id'] ?? $model?->prenotazione_id;
127
+    if ($prenotazioneId) {
128
+      $prenotazione = Prenotazione::with('evento')->find($prenotazioneId);
129
+      if (! $prenotazione || (int) $prenotazione->evento?->attivita_id !== (int) $attivitaId) {
130
+        abort(404);
131
+      }
132
+    }
133
+
134
+    $metodoId = $data['metodo_pagamento_id'] ?? $model?->metodo_pagamento_id;
135
+    $metodo = MetodoPagamento::find($metodoId);
136
+    if (! $metodo || (int) $metodo->attivita_id !== (int) $attivitaId) {
137
+      abort(404);
138
+    }
139
+  }
140
+
141
+}

+ 12
- 12
app/DataTables/PiattoDataTable.php Просмотреть файл

@@ -80,19 +80,19 @@ class PiattoDataTable extends DataTable
80 80
      */
81 81
     public function query(Piatto $model): QueryBuilder
82 82
     {
83
-        if($this->attivita_id !== null){
84
-            $model = $model->newQuery()->where('attivita_id', $this->attivita_id);
85
-            
86
-            if (isset($this->cucina_id)) {
87
-                return $model->where('cucina_id', $this->cucina_id)
88
-                    ->with('cucina', 'elencoAllergeni');
89
-            }
83
+        $attivitaId = (int) $this->attivita_id;
84
+        if ($attivitaId <= 0) {
85
+            return $model->newQuery()->whereRaw('1 = 0');
86
+        }
90 87
 
91
-            return $model->with('cucina', 'elencoAllergeni');
88
+        $model = $model->newQuery()->where('attivita_id', $attivitaId);
92 89
 
93
-        }else{
94
-            return $model->newQuery()->whereRaw('1 = 0');
90
+        if (isset($this->cucina_id)) {
91
+            return $model->where('cucina_id', $this->cucina_id)
92
+                ->with('cucina', 'elencoAllergeni');
95 93
         }
94
+
95
+        return $model->with('cucina', 'elencoAllergeni');
96 96
     }
97 97
 
98 98
     /**
@@ -145,11 +145,11 @@ class PiattoDataTable extends DataTable
145 145
                 Editor::make()
146 146
                     ->ajax(route('piatto.store'))
147 147
                     ->fields([
148
-                        Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
148
+                        Fields\Hidden::make('attivita_id')->label('Attività')->default((int) $this->attivita_id),
149 149
                         Fields\Text::make('nome')->label('Nome'),
150 150
                         Fields\Text::make('descrizione')->label('Descrizione'),
151 151
                         Fields\Select2::make('cucina_id')->label('cucina')
152
-                        ->options(Cucina::where('is_attiva', true)->where('attivita_id', $this->attivita_id)->pluck('id', 'nome'))
152
+                        ->options(Cucina::where('is_attiva', true)->where('attivita_id', (int) $this->attivita_id)->pluck('id', 'nome'))
153 153
                         ->default(isset($this->cucina_id) ? $this->cucina_id : ''),
154 154
                         Fields\Text::make('prezzo')->label('Prezzo (€)'),
155 155
                         // Fields\Image::make('immagine')->label('Immagine'),

+ 28
- 7
app/DataTables/PiattoDataTableEditor.php Просмотреть файл

@@ -2,15 +2,13 @@
2 2
 
3 3
 namespace App\DataTables;
4 4
 
5
+use App\Models\Cucina;
5 6
 use App\Models\Piatto;
6 7
 use App\Models\PiattoHasAllergene;
8
+use App\Services\Attivita\AttivitaService;
7 9
 use Illuminate\Database\Eloquent\Model;
8
-use Illuminate\Validation\Rule;
9 10
 use Yajra\DataTables\DataTablesEditor;
10
-use Illuminate\Http\Request;
11
-use Illuminate\Validation\ValidationException;
12
-use Storage;
13
-use Illuminate\Support\Str;
11
+use Illuminate\Support\Facades\Session;
14 12
 
15 13
 class PiattoDataTableEditor extends DataTablesEditor
16 14
 {
@@ -94,6 +92,10 @@ class PiattoDataTableEditor extends DataTablesEditor
94 92
 
95 93
   public function creating(Model $model, array $data): array
96 94
   {
95
+    $data['attivita_id'] = Session::get('attivita_attuale');
96
+    AttivitaService::garantisciAttivita($data['attivita_id']);
97
+    $this->garantisciCucinaDiQuestaAttivita($data['cucina_id'] ?? null, $data['attivita_id']);
98
+
97 99
     // L'Editor manda `allergeni` come array di ID selezionati:
98 100
     // salviamo la relazione nella pivot `piatto_allergene`, non nella colonna `piatto.allergeni`.
99 101
     $data['_allergeni_ids'] = $this->normalizeAllergeniIds($data['allergeni'] ?? null);
@@ -101,22 +103,41 @@ class PiattoDataTableEditor extends DataTablesEditor
101 103
 
102 104
     $data['bacheca_id'] = isset($data['bacheca_id']) ? true : false;
103 105
     $data['in_evidenza'] = isset($data['in_evidenza']) ? true : false;
104
-    $data['disponibile'] = isset($data['disponibile']) ? true : false;
106
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
105 107
     return $data;
106 108
   }
107 109
 
108 110
   public function updating(Model $model, array $data): array
109 111
   {
112
+    AttivitaService::garantisciAttivita($model->attivita_id);
113
+    unset($data['attivita_id']);
114
+    $this->garantisciCucinaDiQuestaAttivita($data['cucina_id'] ?? $model->cucina_id, $model->attivita_id);
115
+
110 116
     $data['_allergeni_ids'] = $this->normalizeAllergeniIds($data['allergeni'] ?? null);
111 117
     unset($data['allergeni']);
112 118
 
113 119
     $data['bacheca_id'] = isset($data['bacheca_id']) ? true : false;
114 120
     $data['in_evidenza'] = isset($data['in_evidenza']) ? true : false;
115
-    $data['disponibile'] = isset($data['disponibile']) ? true : false;
121
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
116 122
 
117 123
     return $data;
118 124
   }
119 125
 
126
+  public function deleting(Model $model, array $data): array
127
+  {
128
+    AttivitaService::garantisciAttivita($model->attivita_id);
129
+
130
+    return $data;
131
+  }
132
+
133
+  private function garantisciCucinaDiQuestaAttivita($cucinaId, $attivitaId): void
134
+  {
135
+    $cucina = Cucina::find($cucinaId);
136
+    if (! $cucina || (int) $cucina->attivita_id !== (int) $attivitaId) {
137
+      abort(404);
138
+    }
139
+  }
140
+
120 141
   protected function normalizeAllergeniIds(null|array|string $value): array
121 142
   {
122 143
     if (is_null($value)) {

+ 47
- 33
app/DataTables/PrenotazioneDataTable.php Просмотреть файл

@@ -42,6 +42,9 @@ class PrenotazioneDataTable extends DataTable
42 42
             ->addColumn('stato_display', function($entity){
43 43
               return view('prenotazione._partials.stato-prenotazione', ['stato' => $entity->stato??'']);
44 44
             })
45
+            ->addColumn('confermata', function($entity){
46
+              return view('_partials.available', ['available' => $entity->confermata]);
47
+            })
45 48
             ->setRowId('id');
46 49
     }
47 50
 
@@ -52,10 +55,16 @@ class PrenotazioneDataTable extends DataTable
52 55
      */
53 56
     public function query(Prenotazione $model): QueryBuilder
54 57
     {
55
-        if(isset($this->evento_id)){
56
-            return $model->newQuery()->where('evento_id', $this->evento_id);
58
+        $attivitaId = (int) session('attivita_attuale');
59
+        $query = $model->newQuery()->whereHas('evento', function ($q) use ($attivitaId) {
60
+            $q->where('attivita_id', $attivitaId);
61
+        });
62
+
63
+        if (isset($this->evento_id)) {
64
+            $query->where('evento_id', $this->evento_id);
57 65
         }
58
-        return $model->newQuery();
66
+
67
+        return $query;
59 68
     }
60 69
 
61 70
     /**
@@ -64,39 +73,42 @@ class PrenotazioneDataTable extends DataTable
64 73
     public function html(): HtmlBuilder
65 74
     {
66 75
         $titoloPrenotazioni = 'Prenotazione';
67
-        if(isset($this->evento_id)){
68
-            $titoloPrenotazioni = 'Prenota per ' . Evento::find($this->evento_id)->nome;
69
-        }
76
+
70 77
         $buttons = [];
71 78
         if(Auth::user()->can('create-prenotazione')){
72
-            array_push($buttons, Button::make('create')
73
-                ->editor('editor')
74
-                ->className('btn btn-sm btn-primary mb-4')
75
-                ->formTitle('Crea nuovo prenotazione')
76
-                ->formButtons([
77
-                    Button::raw('Annulla')
78
-                        ->className('btn btn-secondary ml-2')
79
-                        ->actionClose(),
80
-                    Button::raw('Salva')
81
-                        ->className('btn btn-success ml-2')
82
-                        ->actionHandler('create')
83
-                ])
84
-                ->text('<i class="fas fa-plus"></i> ' . $titoloPrenotazioni));
79
+            $nuovaUrl = isset($this->evento_id)
80
+                ? route('prenotazione.nuova', ['evento_id' => $this->evento_id])
81
+                : route('prenotazione.nuova');
82
+
83
+            array_push($buttons, Button::raw()
84
+                ->className('btn btn-sm btn-primary mb-4 text-white')
85
+                ->action('window.location.href = '.json_encode($nuovaUrl))
86
+                ->text('<i class="fas fa-plus"></i> Prenotazione'));
87
+            if($this->evento_id){
88
+                array_push($buttons, Button::raw('Conferma tutte le prenotazioni')
89
+                    ->className('btn btn-sm btn-primary mb-4 text-white')
90
+                        ->action('confermaTuttePrenotazioni()')
91
+                        ->text('<i class="fas fa-check"></i> Conferma tutte le prenotazioni')
92
+                    );
93
+            }
94
+
85 95
         };
86 96
 
87
-        if(Auth::user()->can('edit-prenotazione') || Auth::user()->can('segna-presenza-prenotazione')){
88
-            array_push($buttons, Button::raw('Appello')
89
-                ->className('btn btn-sm btn-warning mb-4')
90
-                ->action('appelloPrenotazioni')
91
-            );
92
-        }
97
+        // if(Auth::user()->can('edit-prenotazione') || Auth::user()->can('segna-presenza-prenotazione')){
98
+        //     array_push($buttons, Button::raw('Appello')
99
+        //         ->className('btn btn-sm btn-warning mb-4')
100
+        //         ->action('appelloPrenotazioni')
101
+        //     );
102
+        // }
93 103
 
94 104
         if(Auth::user()->can('report-prenotazione') || Auth::user()->can('segna-presenza-prenotazione')){
105
+            if($this->evento_id){
95 106
             array_push($buttons, Button::raw('Report')
96
-                ->className('btn btn-sm btn-success mb-4')
97
-                ->action('reportPrenotazioni()')
98
-                ->text('<i class="fas fa-file-alt"></i> Report')
99
-            );
107
+                ->className('btn btn-sm btn-primary mb-4 text-white')
108
+                    ->action('reportPrenotazioni()')
109
+                    ->text('<i class="fas fa-file-alt"></i> Report')
110
+                );
111
+            }
100 112
         }
101 113
 
102 114
 
@@ -108,10 +120,11 @@ $fields = [
108 120
         Fields\Text::make('email')->label('Email'),
109 121
         Fields\Text::make('telefono')->label('Telefono'),
110 122
         Fields\Select2::make('evento_id')->label('Evento')
111
-        ->options(Evento::where('is_attivo', true)->pluck('id', 'nome'))
123
+        ->options(Evento::where('attivita_id', session('attivita_attuale'))->orderBy('nome')->pluck('id', 'nome'))
112 124
         ->default(isset($this->evento_id) ? $this->evento_id : ''),
113
-        Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::all()->pluck('id', 'nome')),
125
+        Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::where('attivita_id', session('attivita_attuale'))->orderBy('nome')->pluck('id', 'nome')),
114 126
         Fields\Select2::make('stato')->label('Stato')->options(Prenotazione::getStati()->pluck('value', 'label'))->default(Prenotazione::STATO_INVIATA) ,
127
+        Fields\Boolean::make('confermata')->label('Confermata')->default(false),
115 128
         Fields\Text::make('note')->label('Note'),
116 129
         Fields\Text::make('codice')->label('Codice'),
117 130
         Fields\Text::make('stato_pagamento')->label('Stato pagamento'),
@@ -150,14 +163,15 @@ $fields = [
150 163
         return [
151 164
             Column::make('id')->title('ID')->width('10%')->visible(false)->responsivePriority(1)->width('10%'),
152 165
             Column::make('stato')->data('stato_display')->title('Stato')->searchable(true)->filter(true)->responsivePriority(1),
166
+            Column::make('confermata')->addClass('text-center')->title('Confermata')->responsivePriority(1),
153 167
             Column::make('codice')->title('Codice')->responsivePriority(1),
154 168
             Column::make('cognome')->title('Cognome')->responsivePriority(2),
155 169
             Column::make('nome')->title('Nome'),
156 170
             Column::make('email')->title('Email'),
157 171
             Column::make('telefono')->title('Telefono'),
158 172
             Column::make('evento_id_display')->title('Evento'),
159
-            Column::make('cucina_id_display')->title('Cucina'),
160
-            Column::make('note')->title('Note'),
173
+            // Column::make('cucina_id_display')->title('Cucina'),
174
+            // Column::make('note')->title('Note'),
161 175
             Column::computed('action')
162 176
                   ->title('')
163 177
                   ->exportable(false)

+ 47
- 14
app/DataTables/PrenotazioneDataTableEditor.php Просмотреть файл

@@ -2,20 +2,16 @@
2 2
 
3 3
 namespace App\DataTables;
4 4
 
5
+use App\Models\Cucina;
6
+use App\Models\Evento;
5 7
 use App\Models\Prenotazione;
8
+use App\Services\Attivita\AttivitaService;
6 9
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8 10
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 11
 
14 12
 class PrenotazioneDataTableEditor extends DataTablesEditor
15 13
 {
16 14
   protected $model = Prenotazione::class;
17
-  // protected $uploadDir = '';
18
-  // protected $disk = 'modelliRicevute';
19 15
 
20 16
   protected $messages = [
21 17
     'nome.required' => 'Il nome è richiesto',
@@ -24,7 +20,7 @@ class PrenotazioneDataTableEditor extends DataTablesEditor
24 20
     'telefono.required' => 'Il telefono è richiesto',
25 21
     'evento_id.required' => 'L\'evento è richiesto',
26 22
     'cucina_id.required' => 'La cucina è richiesta',
27
-    'stato.required' => 'Il stato è richiesto',
23
+    'stato.required' => 'Lo stato è richiesto',
28 24
     'note.required' => 'La note è richiesta',
29 25
   ];
30 26
 
@@ -41,8 +37,9 @@ class PrenotazioneDataTableEditor extends DataTablesEditor
41 37
       'email' => 'nullable|email',
42 38
       'telefono' => 'nullable',
43 39
       'evento_id' => 'required|exists:evento,id',
44
-      'cucina_id' => 'required|exists:cucina,id',
40
+      'cucina_id' => 'nullable|exists:cucina,id',
45 41
       'stato' => 'nullable|string',
42
+      'confermata' => 'nullable|boolean',
46 43
       'note' => 'nullable',
47 44
       'codice' => 'required|unique:prenotazione,codice',
48 45
       'stato_pagamento' => 'nullable|string',
@@ -68,10 +65,11 @@ class PrenotazioneDataTableEditor extends DataTablesEditor
68 65
       'email' => 'nullable|email',
69 66
       'telefono' => 'nullable',
70 67
       'evento_id' => 'required|exists:evento,id',
71
-      'cucina_id' => 'required|exists:cucina,id',
68
+      'cucina_id' => 'nullable|exists:cucina,id',
72 69
       'stato' => 'nullable|string',
70
+      'confermata' => 'nullable|boolean',
73 71
       'note' => 'nullable',
74
-      'codice' => 'required|unique:prenotazione,codice',
72
+      'codice' => 'required|unique:prenotazione,codice,'.$model->getKey(),
75 73
     ];
76 74
   }
77 75
 
@@ -92,16 +90,51 @@ class PrenotazioneDataTableEditor extends DataTablesEditor
92 90
 
93 91
   public function creating(Model $model, array $data): array
94 92
   {
95
-    // $model->roles()->sync([$data['ruolo_id']]);
93
+    $evento = $this->eventoDiQuestaAttivita($data['evento_id'] ?? null);
94
+    $this->garantisciCucinaDiQuestaAttivita($data['cucina_id'] ?? null, $evento->attivita_id);
95
+
96 96
     return $data;
97 97
   }
98 98
 
99 99
   public function updating(Model $model, array $data): array
100 100
   {
101
-    // dd($data['ruolo']);
102
-    // $model->roles()->sync([$data['ruolo_id']]);
101
+    $this->eventoDiQuestaAttivita($model->evento_id);
102
+    $evento = $this->eventoDiQuestaAttivita($data['evento_id'] ?? $model->evento_id);
103
+    $this->garantisciCucinaDiQuestaAttivita($data['cucina_id'] ?? $model->cucina_id, $evento->attivita_id);
104
+
103 105
     return $data;
104 106
   }
107
+
108
+  public function deleting(Model $model, array $data): array
109
+  {
110
+    $this->eventoDiQuestaAttivita($model->evento_id);
111
+
112
+    return $data;
113
+  }
114
+
115
+  private function eventoDiQuestaAttivita($eventoId): Evento
116
+  {
117
+    $evento = Evento::find($eventoId);
118
+    if (! $evento) {
119
+      abort(404);
120
+    }
121
+    AttivitaService::garantisciEventoDiQuestaAttivita($evento);
122
+
123
+    return $evento;
124
+  }
125
+
126
+  private function garantisciCucinaDiQuestaAttivita($cucinaId, $attivitaId): void
127
+  {
128
+    if (! $cucinaId) {
129
+      return;
130
+    }
131
+
132
+    $cucina = Cucina::find($cucinaId);
133
+    if (! $cucina || (int) $cucina->attivita_id !== (int) $attivitaId) {
134
+      abort(404);
135
+    }
136
+  }
137
+
105 138
   public function messages(): array
106 139
   {
107 140
     return $this->messages;

+ 30
- 8
app/DataTables/PrenotazioneTavoloDataTableEditor.php Просмотреть файл

@@ -3,13 +3,11 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\PrenotazioneTavolo;
6
+use App\Models\Tavolo;
7
+use App\Services\Attivita\AttivitaService;
6 8
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
10
+use Illuminate\Support\Facades\Session;
13 11
 
14 12
 class PrenotazioneTavoloDataTableEditor extends DataTablesEditor
15 13
 {
@@ -90,16 +88,40 @@ class PrenotazioneTavoloDataTableEditor extends DataTablesEditor
90 88
 
91 89
   public function creating(Model $model, array $data): array
92 90
   {
93
-    // $model->roles()->sync([$data['ruolo_id']]);
91
+    $data['attivita_id'] = Session::get('attivita_attuale');
92
+    AttivitaService::garantisciAttivita($data['attivita_id']);
93
+    $this->garantisciTavoloDiQuestaAttivita($data['tavolo_id'] ?? null, $data['attivita_id']);
94
+
94 95
     return $data;
95 96
   }
96 97
 
97 98
   public function updating(Model $model, array $data): array
98 99
   {
99
-    // dd($data['ruolo']);
100
-    // $model->roles()->sync([$data['ruolo_id']]);
100
+    AttivitaService::garantisciAttivita($model->attivita_id);
101
+    unset($data['attivita_id']);
102
+    $this->garantisciTavoloDiQuestaAttivita($data['tavolo_id'] ?? $model->tavolo_id, $model->attivita_id);
103
+
101 104
     return $data;
102 105
   }
106
+
107
+  public function deleting(Model $model, array $data): array
108
+  {
109
+    AttivitaService::garantisciAttivita($model->attivita_id);
110
+
111
+    return $data;
112
+  }
113
+
114
+  private function garantisciTavoloDiQuestaAttivita($tavoloId, $attivitaId): void
115
+  {
116
+    if (! $tavoloId) {
117
+      return;
118
+    }
119
+
120
+    $tavolo = Tavolo::find($tavoloId);
121
+    if (! $tavolo || (int) $tavolo->attivita_id !== (int) $attivitaId) {
122
+      abort(404);
123
+    }
124
+  }
103 125
   public function messages(): array
104 126
   {
105 127
     return $this->messages;

+ 9
- 6
app/DataTables/PrimaNotaDataTable.php Просмотреть файл

@@ -118,12 +118,14 @@ class PrimaNotaDataTable extends DataTable
118 118
      */
119 119
     public function query(PrimaNota $model): QueryBuilder
120 120
     {
121
-        if (!$this->attivita_id) {
121
+        $attivitaId = (int) $this->attivita_id;
122
+        if ($attivitaId <= 0) {
122 123
             return $model->newQuery()->whereRaw('1 = 0');
123 124
         }
124 125
 
125 126
         return $model->newQuery()
126
-            ->where('attivita_id', $this->attivita_id)
127
+            ->with('pagamento')
128
+            ->where('attivita_id', $attivitaId)
127 129
             ->conFiltriIndice()
128 130
             ->orderBy('created_at', 'desc');
129 131
     }
@@ -195,21 +197,22 @@ class PrimaNotaDataTable extends DataTable
195 197
                     ->editor(
196 198
                         Editor::make()
197 199
                             ->fields([
198
-                                Fields\Hidden::make('attivita_id')->default($this->attivita_id),
200
+                                Fields\Hidden::make('attivita_id')->default((int) $this->attivita_id),
199 201
                                 Fields\Select2::make('tipo_movimento')->label('Tipo movimento')->options(PrimaNota::getTipiMovimento()->pluck('value', 'label')),
200
-                                Fields\Select2::make('categoria_contabile_id')->label('Categoria contabile')->options(\App\Models\Categoriacontabile::where('is_attiva', true)->pluck('id', 'nome')),
202
+                                Fields\Select2::make('categoria_contabile_id')->label('Categoria contabile')->options(\App\Models\Categoriacontabile::where('attivita_id', (int) $this->attivita_id)->where('is_attiva', true)->pluck('id', 'nome')),
203
+                                Fields\Select2::make('pagamento_id')->label('Pagamento')->options(Pagamento::where('attivita_id', (int) $this->attivita_id)->pluck('id', 'causale')),
201 204
                                 Fields\Text::make('importo')->label('Importo'),
202 205
                                 Fields\Text::make('causale')->label('Causale'),
203 206
                                 Fields\Text::make('riferimento')->label('Riferimento'),
204 207
                                 Fields\Select2::make('evento_id')
205 208
                                 ->label('Evento')
206 209
                                 ->options(
207
-                                    collect(['Nessun evento' => ''])->merge(Evento::all()->pluck('id', 'nome'))->toArray()
210
+                                    collect(['Nessun evento' => ''])->merge(Evento::where('attivita_id', (int) $this->attivita_id)->pluck('id', 'nome'))->toArray()
208 211
                                 ),
209 212
                                 Fields\Select2::make('fornitore_id')
210 213
                                 ->label('Fornitore')
211 214
                                 ->options(
212
-                                    collect(['Nessun fornitore' => ''])->merge(Fornitore::all()->pluck('id', 'nome'))->toArray()
215
+                                    collect(['Nessun fornitore' => ''])->merge(Fornitore::where('attivita_id', (int) $this->attivita_id)->pluck('id', 'nome'))->toArray()
213 216
                                 ),
214 217
                                 
215 218
                                 // Fields\Checkbox::make('tipo_movimento')->label('Tipo movimento')->options(PrimaNota::getTipiMovimento()->pluck('value', 'label')),

+ 56
- 20
app/DataTables/PrimaNotaDataTableEditor.php Просмотреть файл

@@ -2,20 +2,21 @@
2 2
 
3 3
 namespace App\DataTables;
4 4
 
5
+use App\Models\Categoriacontabile;
6
+use App\Models\Evento;
7
+use App\Models\Fornitore;
8
+use App\Models\Ordine;
9
+use App\Models\Pagamento;
10
+use App\Models\Prenotazione;
5 11
 use App\Models\PrimaNota;
12
+use App\Services\Attivita\AttivitaService;
6 13
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8 14
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
15
+use Illuminate\Support\Facades\Session;
13 16
 
14 17
 class PrimaNotaDataTableEditor extends DataTablesEditor
15 18
 {
16 19
   protected $model = PrimaNota::class;
17
-  // protected $uploadDir = '';
18
-  // protected $disk = 'modelliRicevute';
19 20
 
20 21
   protected $messages = [
21 22
     'riferimento.required' => 'Il riferimento è richiesto',
@@ -23,7 +24,7 @@ class PrimaNotaDataTableEditor extends DataTablesEditor
23 24
     'importo.required' => 'L\'importo è richiesto',
24 25
     'tipo_movimento.required' => 'Il tipo movimento è richiesto',
25 26
     'causale.required' => 'La causale è richiesta',
26
-    'stato.required' => 'Il stato è richiesto',
27
+    'stato.required' => 'Lo stato è richiesto',
27 28
     'categoria_contabile_id.required' => 'La categoria contabile è richiesta',
28 29
   ];
29 30
 
@@ -35,7 +36,6 @@ class PrimaNotaDataTableEditor extends DataTablesEditor
35 36
   public function createRules(): array
36 37
   {
37 38
     return [
38
-      'attivita_id' => 'required|exists:attivita,id',
39 39
       'pagamento_id' => 'nullable|exists:pagamento,id',
40 40
       'ordine_id' => 'nullable|exists:ordine,id',
41 41
       'prenotazione_id' => 'nullable|exists:prenotazione,id',
@@ -43,12 +43,9 @@ class PrimaNotaDataTableEditor extends DataTablesEditor
43 43
       'fornitore_id' => 'nullable|exists:fornitore,id',
44 44
       'riferimento' => 'nullable|string',
45 45
       'importo' => 'required|numeric',
46
-      'tipo_movimento' => 'required|string',   
46
+      'tipo_movimento' => 'required|string',
47 47
       'causale' => 'required|string',
48 48
       'categoria_contabile_id' => 'required|exists:categoria_contabile,id',
49
-      // 'stato' => 'nullable|string',
50
-      // 'note' => 'nullable|string',
51
-      // 'codice' => 'nullable|string',
52 49
       'stato_pagamento' => 'nullable|string',
53 50
       'metodo_pagamento' => 'nullable|string',
54 51
     ];
@@ -67,7 +64,6 @@ class PrimaNotaDataTableEditor extends DataTablesEditor
67 64
   public function editRules(Model $model): array
68 65
   {
69 66
     return [
70
-      'attivita_id' => 'required|exists:attivita,id',
71 67
       'pagamento_id' => 'nullable|exists:pagamento,id',
72 68
       'ordine_id' => 'nullable|exists:ordine,id',
73 69
       'prenotazione_id' => 'nullable|exists:prenotazione,id',
@@ -75,12 +71,10 @@ class PrimaNotaDataTableEditor extends DataTablesEditor
75 71
       'fornitore_id' => 'nullable|exists:fornitore,id',
76 72
       'riferimento' => 'nullable|string',
77 73
       'importo' => 'required|numeric',
78
-      'tipo_movimento' => 'required|string',   
74
+      'tipo_movimento' => 'required|string',
79 75
       'causale' => 'required|string',
80 76
       'stato' => 'nullable|string',
81 77
       'categoria_contabile_id' => 'required|exists:categoria_contabile,id',
82
-      // 'note' => 'nullable|string',
83
-      // 'codice' => 'nullable|string',
84 78
       'stato_pagamento' => 'nullable|string',
85 79
       'metodo_pagamento' => 'nullable|string',
86 80
     ];
@@ -103,19 +97,61 @@ class PrimaNotaDataTableEditor extends DataTablesEditor
103 97
 
104 98
   public function creating(Model $model, array $data): array
105 99
   {
106
-    // $model->roles()->sync([$data['ruolo_id']]);
100
+    $data['attivita_id'] = Session::get('attivita_attuale');
101
+    AttivitaService::garantisciAttivita($data['attivita_id']);
102
+    $this->garantisciRelazioniDiQuestaAttivita($data, $data['attivita_id']);
103
+
107 104
     return $data;
108 105
   }
109 106
 
110 107
   public function updating(Model $model, array $data): array
111 108
   {
112
-    // dd($data['ruolo']);
113
-    // $model->roles()->sync([$data['ruolo_id']]);
109
+    AttivitaService::garantisciAttivita($model->attivita_id);
110
+    unset($data['attivita_id']);
111
+    $this->garantisciRelazioniDiQuestaAttivita($data, $model->attivita_id, $model);
112
+
113
+    return $data;
114
+  }
115
+
116
+  public function deleting(Model $model, array $data): array
117
+  {
118
+    AttivitaService::garantisciAttivita($model->attivita_id);
119
+
114 120
     return $data;
115 121
   }
122
+
116 123
   public function messages(): array
117 124
   {
118 125
     return $this->messages;
119 126
   }
120 127
 
128
+  private function garantisciRelazioniDiQuestaAttivita(array $data, $attivitaId, ?Model $model = null): void
129
+  {
130
+    $this->garantisciStessoTenant($data['pagamento_id'] ?? $model?->pagamento_id, Pagamento::class, $attivitaId);
131
+    $this->garantisciStessoTenant($data['ordine_id'] ?? $model?->ordine_id, Ordine::class, $attivitaId);
132
+    $this->garantisciStessoTenant($data['evento_id'] ?? $model?->evento_id, Evento::class, $attivitaId);
133
+    $this->garantisciStessoTenant($data['fornitore_id'] ?? $model?->fornitore_id, Fornitore::class, $attivitaId);
134
+    $this->garantisciStessoTenant($data['categoria_contabile_id'] ?? $model?->categoria_contabile_id, Categoriacontabile::class, $attivitaId);
135
+
136
+    $prenotazioneId = $data['prenotazione_id'] ?? $model?->prenotazione_id;
137
+    if ($prenotazioneId) {
138
+      $prenotazione = Prenotazione::with('evento')->find($prenotazioneId);
139
+      if (! $prenotazione || (int) $prenotazione->evento?->attivita_id !== (int) $attivitaId) {
140
+        abort(404);
141
+      }
142
+    }
143
+  }
144
+
145
+  private function garantisciStessoTenant($id, string $class, $attivitaId): void
146
+  {
147
+    if (! $id) {
148
+      return;
149
+    }
150
+
151
+    $record = $class::find($id);
152
+    if (! $record || (int) $record->attivita_id !== (int) $attivitaId) {
153
+      abort(404);
154
+    }
155
+  }
156
+
121 157
 }

+ 16
- 1
app/DataTables/PrintJobDataTable.php Просмотреть файл

@@ -67,7 +67,22 @@ class PrintJobDataTable extends DataTable
67 67
      */
68 68
     public function query(PrintJob $model): QueryBuilder
69 69
     {
70
-        return $model->newQuery()->orderBy('created_at', 'desc');
70
+        $attivitaId = (int) session('attivita_attuale');
71
+        if ($attivitaId <= 0) {
72
+            return $model->newQuery()->whereRaw('1 = 0');
73
+        }
74
+
75
+        return $model->newQuery()
76
+            ->where(function ($q) use ($attivitaId) {
77
+                $q->whereHas('dispositivo', function ($d) use ($attivitaId) {
78
+                    $d->where('attivita_id', $attivitaId);
79
+                })->orWhereHas('stampante', function ($d) use ($attivitaId) {
80
+                    $d->where('attivita_id', $attivitaId);
81
+                })->orWhereHas('ordine', function ($o) use ($attivitaId) {
82
+                    $o->where('attivita_id', $attivitaId);
83
+                });
84
+            })
85
+            ->orderBy('created_at', 'desc');
71 86
     }
72 87
 
73 88
     /**

+ 8
- 1
app/DataTables/PuntoOperatoreDataTable.php Просмотреть файл

@@ -17,6 +17,8 @@ use Illuminate\Support\Facades\Auth;
17 17
 
18 18
 class PuntoOperatoreDataTable extends DataTable
19 19
 {
20
+    public ?int $attivita_id = null;
21
+
20 22
     public function __construct()
21 23
     {
22 24
         $this->dataTableVariable = 'dataTable_punto_operatore';
@@ -45,9 +47,14 @@ class PuntoOperatoreDataTable extends DataTable
45 47
      */
46 48
     public function query(Dispositivo $model): QueryBuilder
47 49
     {
50
+        $attivitaId = (int) $this->attivita_id;
51
+        if ($attivitaId <= 0) {
52
+            return $model->newQuery()->whereRaw('1 = 0');
53
+        }
54
+
48 55
         return $model->newQuery()
49 56
         ->where('tipo', Dispositivo::OPERATORE)
50
-        ->where('attivita_id', $this->attivita_id);
57
+        ->where('attivita_id', $attivitaId);
51 58
     }
52 59
 
53 60
     /**

+ 17
- 7
app/DataTables/PuntoOperatoreDataTableEditor.php Просмотреть файл

@@ -3,9 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
8
+use Illuminate\Support\Facades\Session;
7 9
 use Yajra\DataTables\DataTablesEditor;
8
-use Auth;
9 10
 
10 11
 class PuntoOperatoreDataTableEditor extends DataTablesEditor
11 12
 {
@@ -33,8 +34,7 @@ class PuntoOperatoreDataTableEditor extends DataTablesEditor
33 34
   {
34 35
     return [
35 36
       'nome'  => 'required',
36
-      'attivita_id' => 'required|exists:attivita,id',
37
-      'tipo' => 'required',
37
+      'tipo' => 'required|in:'.Dispositivo::OPERATORE,
38 38
       'licenza' => 'nullable',
39 39
       'url_stampante' => 'nullable',
40 40
       'ubicazione' => 'nullable',
@@ -60,8 +60,7 @@ class PuntoOperatoreDataTableEditor extends DataTablesEditor
60 60
   {
61 61
     return [
62 62
       'nome'  => 'required',
63
-      'attivita_id' => 'required|exists:attivita,id',
64
-      'tipo' => 'required',
63
+      'tipo' => 'required|in:'.Dispositivo::OPERATORE,
65 64
       'licenza' => 'nullable',
66 65
       'url_stampante' => 'nullable',
67 66
       'ubicazione' => 'nullable',
@@ -90,18 +89,29 @@ class PuntoOperatoreDataTableEditor extends DataTablesEditor
90 89
 
91 90
   public function creating(Model $model, array $data): array
92 91
   {
93
-    // L'Editor manda `allergeni` come array di ID selezionati:
94
-    // salviamo la relazione nella pivot `piatto_allergene`, non nella colonna `piatto.allergeni`.
92
+    $data['attivita_id'] = Session::get('attivita_attuale');
93
+    AttivitaService::garantisciAttivita($data['attivita_id']);
94
+    $data['tipo'] = Dispositivo::OPERATORE;
95 95
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
96 96
     return $data;
97 97
   }
98 98
 
99 99
   public function updating(Model $model, array $data): array
100 100
   {
101
+    AttivitaService::garantisciAttivita($model->attivita_id);
102
+    unset($data['attivita_id']);
103
+    $data['tipo'] = Dispositivo::OPERATORE;
101 104
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
102 105
     return $data;
103 106
   }
104 107
 
108
+  public function deleting(Model $model, array $data): array
109
+  {
110
+    AttivitaService::garantisciAttivita($model->attivita_id);
111
+
112
+    return $data;
113
+  }
114
+
105 115
   public function saved(Model $model, array $data): Model
106 116
   {
107 117
     return $model;

+ 8
- 1
app/DataTables/PuntoVenditaDataTable.php Просмотреть файл

@@ -16,6 +16,8 @@ use Illuminate\Support\Facades\Auth;
16 16
 
17 17
 class PuntoVenditaDataTable extends DataTable
18 18
 {
19
+    public ?int $attivita_id = null;
20
+
19 21
     public function __construct()
20 22
     {
21 23
         $this->dataTableVariable = 'dataTable_punto_vendita';
@@ -83,9 +85,14 @@ class PuntoVenditaDataTable extends DataTable
83 85
      */
84 86
     public function query(Dispositivo $model): QueryBuilder
85 87
     {
88
+        $attivitaId = (int) $this->attivita_id;
89
+        if ($attivitaId <= 0) {
90
+            return $model->newQuery()->whereRaw('1 = 0');
91
+        }
92
+
86 93
         return $model->newQuery()
87 94
         ->whereIn('tipo', [Dispositivo::KIOSK, Dispositivo::CASSA , Dispositivo::CAMERIERE])
88
-        ->where('attivita_id', $this->attivita_id);
95
+        ->where('attivita_id', $attivitaId);
89 96
     }
90 97
 
91 98
     /**

+ 17
- 14
app/DataTables/PuntoVenditaDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 10
 
14 11
 class PuntoVenditaDataTableEditor extends DataTablesEditor
15 12
 {
@@ -49,8 +46,7 @@ class PuntoVenditaDataTableEditor extends DataTablesEditor
49 46
   {
50 47
     return [
51 48
       'nome'  => 'required',
52
-      'tipo' => 'required',
53
-      'attivita_id' => 'required|exists:attivita,id',
49
+      'tipo' => 'required|in:'.implode(',', [Dispositivo::CASSA, Dispositivo::KIOSK, Dispositivo::CAMERIERE]),
54 50
       'licenza' => 'nullable',
55 51
       'url_stampante' => 'nullable',
56 52
       'ubicazione' => 'nullable',
@@ -76,8 +72,7 @@ class PuntoVenditaDataTableEditor extends DataTablesEditor
76 72
   {
77 73
     return [
78 74
       'nome'  => 'required',
79
-      'tipo' => 'required',
80
-      'attivita_id' => 'required|exists:attivita,id',
75
+      'tipo' => 'required|in:'.implode(',', [Dispositivo::CASSA, Dispositivo::KIOSK, Dispositivo::CAMERIERE]),
81 76
       'licenza' => 'nullable',
82 77
       'url_stampante' => 'nullable',
83 78
       'ubicazione' => 'nullable',
@@ -106,16 +101,24 @@ class PuntoVenditaDataTableEditor extends DataTablesEditor
106 101
 
107 102
   public function creating(Model $model, array $data): array
108 103
   {
109
-    // $model->roles()->sync([$data['ruolo_id']]);
110
-    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
104
+    $data['attivita_id'] = Session::get('attivita_attuale');
105
+    AttivitaService::garantisciAttivita($data['attivita_id']);
106
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
111 107
     return $data;
112 108
   }
113 109
 
114 110
   public function updating(Model $model, array $data): array
115 111
   {
116
-    // dd($data['ruolo']);
117
-    // $model->roles()->sync([$data['ruolo_id']]);
118
-    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
112
+    AttivitaService::garantisciAttivita($model->attivita_id);
113
+    unset($data['attivita_id']);
114
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
115
+    return $data;
116
+  }
117
+
118
+  public function deleting(Model $model, array $data): array
119
+  {
120
+    AttivitaService::garantisciAttivita($model->attivita_id);
121
+
119 122
     return $data;
120 123
   }
121 124
   public function messages(): array

+ 70
- 39
app/DataTables/RigaFatturazioneDataTable.php Просмотреть файл

@@ -28,24 +28,54 @@ class RigaFatturazioneDataTable extends DataTable
28 28
     {
29 29
         return (new EloquentDataTable($query))
30 30
             ->addColumn('action', function ($entity) {
31
-                return view('fatturazione.menu',['entity' => $entity]);
31
+                return view('fatturazione.menu', ['entity' => $entity]);
32 32
             })
33 33
             ->addColumn('attivita_id', function ($entity) {
34
-                return $entity->attivita->nome??'ND';
34
+                return $entity->attivita->nome ?? 'ND';
35
+            })
36
+            ->filterColumn('attivita_id', function ($query, $keyword) {
37
+                $query->whereHas('attivita', function ($q) use ($keyword) {
38
+                    $q->where('nome', 'like', "%{$keyword}%");
39
+                });
35 40
             })
36 41
             ->addColumn('dispositivo_id', function ($entity) {
37
-                return $entity->dispositivo->nome??'ND';
42
+                return $entity->dispositivo->nome ?? 'ND';
43
+            })
44
+            ->filterColumn('dispositivo_id', function ($query, $keyword) {
45
+                $query->whereHas('dispositivo', function ($q) use ($keyword) {
46
+                    $q->where('nome', 'like', "%{$keyword}%");
47
+                });
38 48
             })
39 49
             ->addColumn('prezzo', function ($entity) {
40 50
                 return number_format($entity->prezzo, 2, ',', '.') . ' €';
41 51
             })
52
+            ->filterColumn('prezzo', function ($query, $keyword) {
53
+                $normalized = str_replace(['€', ' ', ','], ['', '', '.'], $keyword);
54
+                $query->where('prezzo', 'like', "%{$normalized}%");
55
+            })
42 56
             ->addColumn('stato_display', function ($entity) {
43
-                return view('fatturazione.stato',['entity' => $entity]);
57
+                return view('fatturazione.stato', ['entity' => $entity]);
58
+            })
59
+            ->filterColumn('stato', function ($query, $keyword) {
60
+                $query->where('stato', 'like', "%{$keyword}%");
44 61
             })
45 62
             ->addColumn('listino_prezzi_display', function ($entity) {
46 63
                 return optional($entity->listinoPrezzi)->label;
47 64
             })
48
-            ->rawColumns(['note'])
65
+            // La colonna HTML si chiama listino_prezzi_id (name), non listino_prezzi_display
66
+            ->filterColumn('listino_prezzi_id', function ($query, $keyword) {
67
+                $query->whereHas('listinoPrezzi', function ($q) use ($keyword) {
68
+                    $q->where('label', 'like', "%{$keyword}%")
69
+                        ->orWhere('descrizione', 'like', "%{$keyword}%");
70
+                });
71
+            })
72
+            ->addColumn('note_display', function ($entity) {
73
+                return $entity->note;
74
+            })
75
+            ->filterColumn('note_display', function ($query, $keyword) {
76
+                $query->where('note', 'like', "%{$keyword}%");
77
+            })
78
+            ->rawColumns(['action', 'stato_display', 'note_display'])
49 79
             ->setRowId('id');
50 80
     }
51 81
 
@@ -56,23 +86,24 @@ class RigaFatturazioneDataTable extends DataTable
56 86
      */
57 87
     public function query(RigaFatturazione $model): QueryBuilder
58 88
     {
59
-        $query = $model->newQuery()->orderBy('created_at', 'desc');
89
+        $query = $model->newQuery()
90
+            ->with(['attivita', 'dispositivo', 'listinoPrezzi'])
91
+            ->orderBy('created_at', 'desc');
60 92
 
61
-        if(!$this->tutti_i_consumi){
93
+        if (! $this->tutti_i_consumi) {
62 94
             $query->whereIn('stato', [RigaFatturazione::GRATUITO, RigaFatturazione::REGISTRATO]);
63 95
         }
64
-        if($this->superadmin){
96
+
97
+        if ($this->superadmin) {
65 98
             return $query;
66
-            }
67
-            
68
-            if($this->user_id){
69
-                $query->where('user_id', $this->user_id);
70
-            }
71
-            if($this->attivita_id){
72
-                $query->where('attivita_id', $this->attivita_id);
73
-            }
99
+        }
100
+
101
+        $attivitaId = (int) $this->attivita_id;
102
+        if ($attivitaId <= 0) {
103
+            return $query->whereRaw('1 = 0');
104
+        }
74 105
 
75
-        return $query;
106
+        return $query->where('attivita_id', $attivitaId);
76 107
     }
77 108
 
78 109
     /**
@@ -149,31 +180,31 @@ class RigaFatturazioneDataTable extends DataTable
149 180
      */
150 181
     public function getColumns(): array
151 182
     {
152
-        return [
153
-            Column::make('id'),
154
-            Column::make('fattura_id')->title('Fattura'),
155
-            Column::make('attivita_id')->title('Attività')->searchable(true)->searchPanes(['show' => true]),
156
-            Column::make('dispositivo_id')->title('Dispositivo')->searchPanes(['show' => true]),
157
-            Column::make('tipo')->title('Tipo'),
158
-            Column::make('qta')->title('Qta'),
159
-            Column::make('ordini')->title('Ordini'),
160
-            Column::make('listino_prezzi_id')->title('Listino prezzi')->data('listino_prezzi_display'),
161
-            Column::make('prezzo'),
162
-            Column::make('stato')->data('stato_display'),
163
-            Column::make('note'),
183
+        $columns = [
184
+            Column::make('id')->searchable(true),
185
+            Column::make('fattura_id')->title('Fattura')->responsivePriority(2)->width('10%'),
186
+            Column::make('attivita_id')->title('Attività')->searchable(true),
187
+            Column::make('dispositivo_id')->title('Dispositivo')->responsivePriority(2)->width('10%')->searchable(true),
188
+            Column::make('tipo')->title('Tipo')->searchable(true),
189
+            Column::make('qta')->title('Qta')->searchable(true),
190
+            Column::make('ordini')->title('Ordini')->searchable(true),
191
+            Column::make('listino_prezzi_id')->title('Listino prezzi')->data('listino_prezzi_display')->name('listino_prezzi_id')->searchable(true),
192
+            Column::make('prezzo')->title('Prezzo')->responsivePriority(1)->width('15%')->searchable(true),
193
+            Column::make('stato')->data('stato_display')->name('stato')->searchable(true),
194
+            Column::make('note_display')->title('Note')->responsivePriority(2)->searchable(true),
164 195
         ];
165 196
 
166
-        if(Auth::user()->hasRole('superadmin')){
167
-            array_push($columns,
168
-            Column::make('action')
169
-                  ->title('')
170
-                  ->addClass('text-center')
171
-                  ->exportable(false)
172
-                  ->printable(false)
173
-                  ->width(60)
174
-                  ->addClass('text-center'),
175
-            );
197
+        if (Auth::user()->hasRole('superadmin')) {
198
+            $columns[] = Column::make('action')
199
+                ->title('')
200
+                ->exportable(false)
201
+                ->printable(false)
202
+                ->searchable(false)
203
+                ->orderable(false)
204
+                ->width(60)
205
+                ->addClass('text-center');
176 206
         }
207
+
177 208
         return $columns;
178 209
     }
179 210
 

+ 34
- 36
app/DataTables/RigaFatturazioneDataTableEditor.php Просмотреть файл

@@ -3,19 +3,16 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\RigaFatturazione;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
-use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
8
+use Illuminate\Support\Facades\Auth;
9
+use Illuminate\Support\Facades\Session;
10 10
 use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
11
+use Yajra\DataTables\DataTablesEditor;
13 12
 
14 13
 class RigaFatturazioneDataTableEditor extends DataTablesEditor
15 14
 {
16 15
   protected $model = RigaFatturazione::class;
17
-  // protected $uploadDir = '';
18
-  // protected $disk = 'modelliRicevute';
19 16
 
20 17
   protected $messages = [
21 18
     'attivita_id.required' => 'L\'attività è richiesta',
@@ -25,53 +22,32 @@ class RigaFatturazioneDataTableEditor extends DataTablesEditor
25 22
     'listino_prezzi_id.required' => 'Il listino prezzi è richiesto',
26 23
   ];
27 24
 
28
-  /**
29
-  * Get create action validation rules.
30
-  *
31
-  * @return array
32
-  */
33 25
   public function createRules(): array
34 26
   {
35 27
     return [
36
-      'attivita_id'  => 'required',
37 28
       'qta' => 'required',
38
-      // 'prezzo' => 'required',
39
-      // 'tipo' => 'required',
40 29
       'listino_prezzi_id' => 'required',
41 30
     ];
42 31
   }
43 32
 
44
-  public function createMessages(): array{
33
+  public function createMessages(): array
34
+  {
45 35
     return $this->messages;
46 36
   }
47 37
 
48
-  /**
49
-  * Get edit action validation rules.
50
-  *
51
-  * @param Model $model
52
-  * @return array
53
-  */
54 38
   public function editRules(Model $model): array
55 39
   {
56 40
     return [
57
-      'attivita_id'  => 'required',
58 41
       'qta' => 'required',
59
-      // 'prezzo' => 'required',
60
-      // 'tipo' => 'required',
61 42
       'listino_prezzi_id' => 'required',
62 43
     ];
63 44
   }
64 45
 
65
-  public function editMessages(): array{
46
+  public function editMessages(): array
47
+  {
66 48
     return $this->messages;
67 49
   }
68 50
 
69
-  /**
70
-  * Get remove action validation rules.
71
-  *
72
-  * @param Model $model
73
-  * @return array
74
-  */
75 51
   public function removeRules(Model $model): array
76 52
   {
77 53
     return [];
@@ -79,22 +55,44 @@ class RigaFatturazioneDataTableEditor extends DataTablesEditor
79 55
 
80 56
   public function creating(Model $model, array $data): array
81 57
   {
82
-    // $model->roles()->sync([$data['ruolo_id']]);
83
-   $listinoPrezzi = \App\Models\ListinoPrezzi::find($data['listino_prezzi_id']);
58
+    $data['attivita_id'] = Session::get('attivita_attuale');
59
+    AttivitaService::garantisciAttivita($data['attivita_id']);
60
+    $data['user_id'] = Auth::id();
61
+    $listinoPrezzi = \App\Models\ListinoPrezzi::find($data['listino_prezzi_id']);
84 62
     $data['prezzo'] = $listinoPrezzi->prezzo;
85 63
     $data['tipo'] = $listinoPrezzi->categoria;
64
+
86 65
     return $data;
87 66
   }
88 67
 
89 68
   public function updating(Model $model, array $data): array
90 69
   {
91
-    // dd($data['ruolo']);
92
-    // $model->roles()->sync([$data['ruolo_id']]);
70
+    AttivitaService::garantisciAttivita($model->attivita_id);
71
+    $this->assertModificabile($model);
72
+    unset($data['attivita_id'], $data['stato'], $data['ordini'], $data['metadata'], $data['fattura_id']);
73
+
74
+    return $data;
75
+  }
76
+
77
+  public function deleting(Model $model, array $data): array
78
+  {
79
+    AttivitaService::garantisciAttivita($model->attivita_id);
80
+    $this->assertModificabile($model);
81
+
93 82
     return $data;
94 83
   }
84
+
95 85
   public function messages(): array
96 86
   {
97 87
     return $this->messages;
98 88
   }
99 89
 
90
+  private function assertModificabile(Model $model): void
91
+  {
92
+    if (! $model instanceof RigaFatturazione || ! $model->isModificabile()) {
93
+      throw ValidationException::withMessages([
94
+        'stato' => 'Solo le righe in stato gratuito possono essere modificate o eliminate.',
95
+      ]);
96
+    }
97
+  }
100 98
 }

+ 19
- 14
app/DataTables/StampanteDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 10
 
14 11
 class StampanteDataTableEditor extends DataTablesEditor
15 12
 {
@@ -49,8 +46,7 @@ class StampanteDataTableEditor extends DataTablesEditor
49 46
   {
50 47
     return [
51 48
       'nome'  => 'required',
52
-      'tipo' => 'required',
53
-      'attivita_id' => 'required|exists:attivita,id',
49
+      'tipo' => 'required|in:'.Dispositivo::STAMPANTE,
54 50
       'licenza' => 'nullable',
55 51
       'url_stampante' => 'nullable',
56 52
       'ubicazione' => 'nullable',
@@ -76,8 +72,7 @@ class StampanteDataTableEditor extends DataTablesEditor
76 72
   {
77 73
     return [
78 74
       'nome'  => 'required',
79
-      'tipo' => 'required',
80
-      'attivita_id' => 'required|exists:attivita,id',
75
+      'tipo' => 'required|in:'.Dispositivo::STAMPANTE,
81 76
       'licenza' => 'nullable',
82 77
       'url_stampante' => 'nullable',
83 78
       'ubicazione' => 'nullable',
@@ -106,16 +101,26 @@ class StampanteDataTableEditor extends DataTablesEditor
106 101
 
107 102
   public function creating(Model $model, array $data): array
108 103
   {
109
-    // $model->roles()->sync([$data['ruolo_id']]);
110
-    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
104
+    $data['attivita_id'] = Session::get('attivita_attuale');
105
+    AttivitaService::garantisciAttivita($data['attivita_id']);
106
+    $data['tipo'] = Dispositivo::STAMPANTE;
107
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
111 108
     return $data;
112 109
   }
113 110
 
114 111
   public function updating(Model $model, array $data): array
115 112
   {
116
-    // dd($data['ruolo']);
117
-    // $model->roles()->sync([$data['ruolo_id']]);
118
-    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
113
+    AttivitaService::garantisciAttivita($model->attivita_id);
114
+    unset($data['attivita_id']);
115
+    $data['tipo'] = Dispositivo::STAMPANTE;
116
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
117
+    return $data;
118
+  }
119
+
120
+  public function deleting(Model $model, array $data): array
121
+  {
122
+    AttivitaService::garantisciAttivita($model->attivita_id);
123
+
119 124
     return $data;
120 125
   }
121 126
   public function messages(): array

+ 7
- 4
app/DataTables/TavoloDataTable.php Просмотреть файл

@@ -15,6 +15,8 @@ use Illuminate\Support\Facades\Auth;
15 15
 
16 16
 class TavoloDataTable extends DataTable
17 17
 {
18
+    public ?int $attivita_id = null;
19
+
18 20
     public function __construct(){
19 21
         $this->dataTableVariable = 'dataTable_tavolo';
20 22
     }
@@ -42,11 +44,12 @@ class TavoloDataTable extends DataTable
42 44
      */
43 45
     public function query(Tavolo $model): QueryBuilder
44 46
     {
45
-        if($this->attivita_id){
46
-            return $model->newQuery()->where('attivita_id', $this->attivita_id);
47
-        }else{
47
+        $attivitaId = (int) $this->attivita_id;
48
+        if ($attivitaId <= 0) {
48 49
             return $model->newQuery()->whereRaw('1 = 0');
49 50
         }
51
+
52
+        return $model->newQuery()->where('attivita_id', $attivitaId);
50 53
     }
51 54
 
52 55
     /**
@@ -81,7 +84,7 @@ class TavoloDataTable extends DataTable
81 84
                     ->editor(
82 85
                         Editor::make()
83 86
                             ->fields([
84
-                                Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
87
+                                Fields\Hidden::make('attivita_id')->label('Attività')->default((int) $this->attivita_id),
85 88
                                 Fields\Text::make('label')->label('Label'),
86 89
                                 Fields\Text::make('posti')->label('Posti'),
87 90
                                 Fields\Text::make('ubicazione')->label('Ubicazione'),

+ 13
- 10
app/DataTables/TavoloDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Tavolo;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8 8
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
9
+use Illuminate\Support\Facades\Session;
13 10
 
14 11
 class TavoloDataTableEditor extends DataTablesEditor
15 12
 {
@@ -33,7 +30,6 @@ class TavoloDataTableEditor extends DataTablesEditor
33 30
   {
34 31
     return [
35 32
       'label'  => 'required',
36
-      'attivita_id' => 'required|exists:attivita,id',
37 33
       'posti' => 'nullable|numeric|min:0',
38 34
       'ubicazione' => 'nullable',
39 35
       'is_attivo' => 'boolean',
@@ -54,7 +50,6 @@ class TavoloDataTableEditor extends DataTablesEditor
54 50
   {
55 51
     return [
56 52
       'label'  => 'required',
57
-      'attivita_id' => 'required|exists:attivita,id',
58 53
       'posti' => 'nullable|numeric|min:0',
59 54
       'ubicazione' => 'nullable',
60 55
       'is_attivo' => 'boolean',
@@ -78,18 +73,26 @@ class TavoloDataTableEditor extends DataTablesEditor
78 73
 
79 74
   public function creating(Model $model, array $data): array
80 75
   {
81
-    // $model->roles()->sync([$data['ruolo_id']]);
76
+    $data['attivita_id'] = Session::get('attivita_attuale');
77
+    AttivitaService::garantisciAttivita($data['attivita_id']);
82 78
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
83 79
     return $data;
84 80
   }
85 81
 
86 82
   public function updating(Model $model, array $data): array
87 83
   {
88
-    // dd($data['ruolo']);
89
-    // $model->roles()->sync([$data['ruolo_id']]);
84
+    AttivitaService::garantisciAttivita($model->attivita_id);
85
+    unset($data['attivita_id']);
90 86
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
91 87
     return $data;
92 88
   }
89
+
90
+  public function deleting(Model $model, array $data): array
91
+  {
92
+    AttivitaService::garantisciAttivita($model->attivita_id);
93
+
94
+    return $data;
95
+  }
93 96
   public function messages(): array
94 97
   {
95 98
     return $this->messages;

+ 13
- 10
app/DataTables/TestiDataTableEditor.php Просмотреть файл

@@ -3,13 +3,10 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\Testi;
6
+use App\Services\Attivita\AttivitaService;
6 7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8 9
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
13 10
 
14 11
 class TestiDataTableEditor extends DataTablesEditor
15 12
 {
@@ -35,7 +32,6 @@ class TestiDataTableEditor extends DataTablesEditor
35 32
   {
36 33
     return [
37 34
       'titolo'  => 'required',
38
-      'attivita_id' => 'required|exists:attivita,id',
39 35
       'descrizione' => 'nullable',
40 36
       'testo' => 'nullable',
41 37
       'ambiente' => 'nullable',
@@ -58,7 +54,6 @@ class TestiDataTableEditor extends DataTablesEditor
58 54
   {
59 55
     return [
60 56
       'titolo'  => 'required',
61
-      'attivita_id' => 'required|exists:attivita,id',
62 57
       'descrizione' => 'nullable',
63 58
       'testo' => 'nullable',
64 59
       'ambiente' => 'nullable',
@@ -84,18 +79,26 @@ class TestiDataTableEditor extends DataTablesEditor
84 79
 
85 80
   public function creating(Model $model, array $data): array
86 81
   {
87
-    // $model->roles()->sync([$data['ruolo_id']]);
82
+    $data['attivita_id'] = Session::get('attivita_attuale');
83
+    AttivitaService::garantisciAttivita($data['attivita_id']);
88 84
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
89 85
     return $data;
90 86
   }
91 87
 
92 88
   public function updating(Model $model, array $data): array
93 89
   {
94
-    // dd($data['ruolo']);
95
-    // $model->roles()->sync([$data['ruolo_id']]);
90
+    AttivitaService::garantisciAttivita($model->attivita_id);
91
+    unset($data['attivita_id']);
96 92
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
97 93
     return $data;
98 94
   }
95
+
96
+  public function deleting(Model $model, array $data): array
97
+  {
98
+    AttivitaService::garantisciAttivita($model->attivita_id);
99
+
100
+    return $data;
101
+  }
99 102
   public function messages(): array
100 103
   {
101 104
     return $this->messages;

+ 10
- 5
app/DataTables/VariantePiattoDataTable.php Просмотреть файл

@@ -58,7 +58,12 @@ class VariantePiattoDataTable extends DataTable
58 58
      */
59 59
     public function query(VariantePiatto $model): QueryBuilder
60 60
     {
61
-        $query = $model->newQuery()->where('attivita_id', $this->attivita_id);
61
+        $attivitaId = (int) $this->attivita_id;
62
+        if ($attivitaId <= 0) {
63
+            return $model->newQuery()->whereRaw('1 = 0');
64
+        }
65
+
66
+        $query = $model->newQuery()->where('attivita_id', $attivitaId);
62 67
         if (isset($this->cucina_id)) {
63 68
             $query->where('cucina_id', $this->cucina_id);
64 69
         }
@@ -92,12 +97,12 @@ class VariantePiattoDataTable extends DataTable
92 97
                     ->editor(Editor::make()
93 98
                         ->ajax(route('variante-piatto.store'))
94 99
                         ->fields([
95
-                            Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
100
+                            Fields\Hidden::make('attivita_id')->label('Attività')->default((int) $this->attivita_id),
96 101
                             Fields\Text::make('label')->label('Nome'),
97 102
                             Fields\Text::make('prezzo')->label('Prezzo'),
98
-                            Fields\Select2::make('piatto_id')->label('Associa al Piatto')->options(Piatto::where('attivita_id', $this->attivita_id)->pluck('id', 'nome')),
99
-                            Fields\Select2::make('cucina_id')->label('Associa alla Cucina')->options(Cucina::where('attivita_id', $this->attivita_id)->pluck('id', 'nome'))->default($this->cucina_id),
100
-                            Fields\Checkbox::make('is_attivo')->label('Attiva')->default(true),
103
+                            Fields\Select2::make('piatto_id')->label('Associa al Piatto')->options(Piatto::where('attivita_id', (int) $this->attivita_id)->pluck('id', 'nome')),
104
+                            Fields\Select2::make('cucina_id')->label('Associa alla Cucina')->options(Cucina::where('attivita_id', (int) $this->attivita_id)->pluck('id', 'nome'))->default($this->cucina_id),
105
+                            Fields\Boolean::make('is_attivo')->label('Attiva')->default(true),
101 106
                         ])
102 107
                     )
103 108
                     ->language(asset('assets/Italian.json'))

+ 36
- 9
app/DataTables/VariantePiattoDataTableEditor.php Просмотреть файл

@@ -2,14 +2,13 @@
2 2
 
3 3
 namespace App\DataTables;
4 4
 
5
+use App\Models\Cucina;
6
+use App\Models\Piatto;
5 7
 use App\Models\VariantePiatto;
8
+use App\Services\Attivita\AttivitaService;
6 9
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8 10
 use Yajra\DataTables\DataTablesEditor;
9
-use Illuminate\Http\Request;
10
-use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
11
+use Illuminate\Support\Facades\Session;
13 12
 
14 13
 class VariantePiattoDataTableEditor extends DataTablesEditor
15 14
 {
@@ -38,9 +37,7 @@ class VariantePiattoDataTableEditor extends DataTablesEditor
38 37
   {
39 38
     return [
40 39
       'label'  => 'required',
41
-      'attivita_id' => 'required|exists:attivita,id',
42 40
       'prezzo' => 'required',
43
-      'is_attivo' => 'boolean',
44 41
       'piatto_id' => 'nullable|exists:piatto,id',
45 42
       'cucina_id' => 'required|exists:cucina,id',
46 43
     ];
@@ -60,9 +57,7 @@ class VariantePiattoDataTableEditor extends DataTablesEditor
60 57
   {
61 58
     return [
62 59
       'label'  => 'required',
63
-      'attivita_id' => 'required|exists:attivita,id',
64 60
       'prezzo' => 'required',
65
-      'is_attivo' => 'boolean',
66 61
       'piatto_id' => 'nullable|exists:piatto,id',
67 62
       'cucina_id' => 'required|exists:cucina,id',
68 63
     ];
@@ -86,6 +81,10 @@ class VariantePiattoDataTableEditor extends DataTablesEditor
86 81
 
87 82
   public function creating(Model $model, array $data): array
88 83
   {
84
+    $data['attivita_id'] = Session::get('attivita_attuale');
85
+    AttivitaService::garantisciAttivita($data['attivita_id']);
86
+    $this->garantisciRelazioniDiQuestaAttivita($data, $data['attivita_id']);
87
+
89 88
     $data['is_attivo'] = array_key_exists('is_attivo', $data)
90 89
       ? filter_var($data['is_attivo'], FILTER_VALIDATE_BOOLEAN)
91 90
       : true;
@@ -94,11 +93,39 @@ class VariantePiattoDataTableEditor extends DataTablesEditor
94 93
 
95 94
   public function updating(Model $model, array $data): array
96 95
   {
96
+    AttivitaService::garantisciAttivita($model->attivita_id);
97
+    unset($data['attivita_id']);
98
+    $this->garantisciRelazioniDiQuestaAttivita($data, $model->attivita_id, $model);
99
+
97 100
     if (array_key_exists('is_attivo', $data)) {
98 101
       $data['is_attivo'] = filter_var($data['is_attivo'], FILTER_VALIDATE_BOOLEAN);
99 102
     }
100 103
     return $data;
101 104
   }
105
+
106
+  public function deleting(Model $model, array $data): array
107
+  {
108
+    AttivitaService::garantisciAttivita($model->attivita_id);
109
+
110
+    return $data;
111
+  }
112
+
113
+  private function garantisciRelazioniDiQuestaAttivita(array $data, $attivitaId, ?Model $model = null): void
114
+  {
115
+    $cucinaId = $data['cucina_id'] ?? $model?->cucina_id;
116
+    $cucina = Cucina::find($cucinaId);
117
+    if (! $cucina || (int) $cucina->attivita_id !== (int) $attivitaId) {
118
+      abort(404);
119
+    }
120
+
121
+    $piattoId = $data['piatto_id'] ?? $model?->piatto_id;
122
+    if ($piattoId) {
123
+      $piatto = Piatto::find($piattoId);
124
+      if (! $piatto || (int) $piatto->attivita_id !== (int) $attivitaId) {
125
+        abort(404);
126
+      }
127
+    }
128
+  }
102 129
   public function messages(): array
103 130
   {
104 131
     return $this->messages;

+ 2
- 0
app/Http/Controllers/AllergeneController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Allergene;
7 9
 use App\DataTables\AllergeneDataTable;

+ 13
- 0
app/Http/Controllers/AsportoController.php Просмотреть файл

@@ -3,6 +3,7 @@
3 3
 namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6
+use Illuminate\Routing\Controllers\Middleware;
6 7
 use App\Models\Asporto;
7 8
 use Illuminate\Support\Collection;
8 9
 
@@ -14,6 +15,18 @@ class AsportoController extends Controller
14 15
         'view-asporto' => 'Visualizza asporto',
15 16
     ];
16 17
 
18
+    public static function middleware(): array
19
+    {
20
+        return [
21
+            new Middleware('permission:view-asporto', only: [
22
+                'index', 'dashboard', 'dashboard_slot',
23
+                'preparazione', 'completaPreparazione',
24
+                'chiamata', 'completaChiamata',
25
+                'ritiro', 'completaRitiro', 'sync',
26
+            ]),
27
+        ];
28
+    }
29
+
17 30
     public function index(Request $request)
18 31
     {
19 32
 

+ 46
- 9
app/Http/Controllers/AttivitaController.php Просмотреть файл

@@ -2,8 +2,11 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Attivita;
9
+use App\Models\Evento;
7 10
 use App\DataTables\AttivitaDataTable;
8 11
 use App\DataTables\AttivitaDataTableEditor;
9 12
 use Illuminate\Support\Facades\Auth;
@@ -24,7 +27,8 @@ class AttivitaController extends Controller
24 27
     public static function middleware(): array
25 28
     {
26 29
         return [
27
-            new Middleware('permission:view-attivita', only: ['index']),
30
+            new Middleware('permission:view-attivita', only: ['index', 'show']),
31
+            new Middleware('permission:select-attivita', only: ['select']),
28 32
             new Middleware('permission:create-attivita|edit-attivita|delete-attivita', only: ['store', 'update', 'destroy']),
29 33
         ];
30 34
     }
@@ -57,13 +61,22 @@ class AttivitaController extends Controller
57 61
 
58 62
     public function show($attivita_id)
59 63
     {
60
-        $attivita = Attivita::with([
64
+        $attivita = Attivita::find($attivita_id);
65
+        $user = Auth::user();
66
+        $isSuperadmin = $user?->hasRole('superadmin');
67
+        $isOwner = $attivita && (int) $attivita->user_id === (int) $user->id;
68
+
69
+        if (! $attivita || (! $isSuperadmin && ! $isOwner)) {
70
+            abort(404);
71
+        }
72
+
73
+        $attivita->load([
61 74
             'dispositivi',
62 75
             'eventi',
63 76
             'prenotazioni',
64 77
             'piatti',
65 78
             'fornitori',
66
-        ])->find($attivita_id);
79
+        ]);
67 80
 
68 81
         return view('attivita.show', ['attivita' => $attivita]);
69 82
     }
@@ -71,9 +84,24 @@ class AttivitaController extends Controller
71 84
     public function select(Request $request)
72 85
     {
73 86
         $request->validate([
74
-            'attivita_id' => 'required|exists:attivita,id',
87
+            'attivita_id' => 'required|integer',
75 88
         ]);
76
-        Session::put('attivita_attuale', $request->attivita_id);
89
+
90
+        $attivita = Attivita::find($request->attivita_id);
91
+        $user = Auth::user();
92
+        $isSuperadmin = $user?->hasRole('superadmin');
93
+        $isOwner = $attivita && (int) $attivita->user_id === (int) $user->id;
94
+
95
+        if (! $attivita || (! $isSuperadmin && ! $isOwner)) {
96
+            abort(404);
97
+        }
98
+
99
+        if (! $attivita->is_attiva) {
100
+            return redirect()->route('attivita.index')->with('error', 'Attività non attiva');
101
+        }
102
+
103
+        Session::put('attivita_attuale', (int) $attivita->id);
104
+
77 105
         return redirect()->route('dashboard')->with('success', 'Attività selezionata con successo');
78 106
     }
79 107
 
@@ -88,12 +116,21 @@ class AttivitaController extends Controller
88 116
         ]);
89 117
     }
90 118
 
91
-    public function show_public(Request $request)
119
+    public function show_public($slug)
92 120
     {
93
-        $attivita = Attivita::find($request->attivita_id);
94
-        if(!$attivita) {
121
+        $attivita = Attivita::where('slug', $slug)->first();
122
+        if (! $attivita) {
95 123
             return redirect()->route('welcome')->with('error', 'Attività non trovata');
96 124
         }
97
-        return view('attivita.public.show', ['attivita' => $attivita]);
125
+
126
+        $eventiPubblici = Evento::pubblici($attivita->id)
127
+            ->orderBy('data_inizio')
128
+            ->orderBy('id')
129
+            ->get();
130
+
131
+        return view('attivita.public.show', [
132
+            'attivita' => $attivita,
133
+            'eventiPubblici' => $eventiPubblici,
134
+        ]);
98 135
     }
99 136
 }

+ 9
- 1
app/Http/Controllers/BachecaController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Bacheca;
7 9
 use App\DataTables\BachecaDataTable;
@@ -9,6 +11,7 @@ use App\DataTables\BachecaDataTableEditor;
9 11
 use Illuminate\Support\Facades\Auth;
10 12
 use App\DataTables\ContenutoBachecaDataTable;
11 13
 use Illuminate\Support\Facades\Session;
14
+use App\Services\Attivita\AttivitaService;
12 15
 
13 16
 class BachecaController extends Controller
14 17
 {
@@ -23,7 +26,7 @@ class BachecaController extends Controller
23 26
     public static function middleware(): array
24 27
     {
25 28
         return [
26
-            new Middleware('permission:view-bacheca', only: ['index']),
29
+            new Middleware('permission:view-bacheca', only: ['index', 'show']),
27 30
             new Middleware('permission:create-bacheca|edit-bacheca|delete-bacheca', only: ['store', 'update', 'destroy']),
28 31
         ];
29 32
     }
@@ -57,6 +60,11 @@ class BachecaController extends Controller
57 60
     public function show(ContenutoBachecaDataTable $datatable, Request $request)
58 61
     {
59 62
         $bacheca = Bacheca::find($request->get('bacheca_id'));
63
+        if (! $bacheca) {
64
+            abort(404);
65
+        }
66
+        AttivitaService::garantisciAttivita($bacheca->attivita_id);
67
+        $datatable->attivita_id = Session::get('attivita_attuale');
60 68
         $datatable->bacheca_id = $bacheca->id;
61 69
         return $datatable->render('bacheca.show', ['bacheca' => $bacheca]);
62 70
     }

+ 14
- 4
app/Http/Controllers/BachecaHasContenutoController.php Просмотреть файл

@@ -2,12 +2,15 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\BachecaHasContenuto;
7 9
 use App\Models\Bacheca;
8 10
 use App\Models\ContenutoBacheca;
9 11
 use Illuminate\Support\Facades\Auth;
10 12
 use Illuminate\Support\Facades\Session;
13
+use App\Services\Attivita\AttivitaService;
11 14
 
12 15
 class BachecaHasContenutoController extends Controller
13 16
 {
@@ -22,8 +25,8 @@ class BachecaHasContenutoController extends Controller
22 25
     public static function middleware(): array
23 26
     {
24 27
         return [
25
-            new Middleware('permission:view-bacheca_has_contenuto', only: ['index']),
26
-            new Middleware('permission:create-bacheca_has_contenuto|edit-bacheca_has_contenuto|delete-bacheca_has_contenuto', only: ['store', 'update', 'destroy']),
28
+            new Middleware('permission:view-bacheca_has_contenuto', only: ['index', 'associa_contenuto']),
29
+            new Middleware('permission:create-bacheca_has_contenuto|edit-bacheca_has_contenuto|delete-bacheca_has_contenuto', only: ['store', 'update', 'destroy', 'associa_contenuto_bacheca']),
27 30
         ];
28 31
     }
29 32
     
@@ -34,7 +37,9 @@ class BachecaHasContenutoController extends Controller
34 37
 
35 38
     public function associa_contenuto(Request $request)
36 39
     {
37
-        $contenuti = ContenutoBacheca::all();
40
+        $attivitaId = Session::get('attivita_attuale');
41
+        AttivitaService::garantisciAttivita($attivitaId);
42
+        $contenuti = ContenutoBacheca::query()->where('attivita_id', $attivitaId)->get();
38 43
         return view('contenuto_bacheca.associa_contenuto', ['contenuti' => $contenuti]);
39 44
     }
40 45
 
@@ -47,7 +52,12 @@ class BachecaHasContenutoController extends Controller
47 52
         
48 53
         $bacheca = Bacheca::find($request->bacheca_id);
49 54
         $contenuto = ContenutoBacheca::find($request->contenuto_id);
50
-        
55
+        if (! $bacheca || ! $contenuto) {
56
+            abort(404);
57
+        }
58
+        AttivitaService::garantisciAttivita($bacheca->attivita_id);
59
+        AttivitaService::garantisciAttivita($contenuto->attivita_id);
60
+
51 61
         $bacheca->contenuti()->attach($contenuto);
52 62
         
53 63
         return response()->json(['message' => 'Contenuto associato con successo']);

+ 15
- 4
app/Http/Controllers/BilancioController.php Просмотреть файл

@@ -35,6 +35,9 @@ class BilancioController extends Controller
35 35
     public function oggi(Request $request, BilancioServizioService $bilancioServizio)
36 36
     {
37 37
         $attivitaId = (int) session()->get('attivita_attuale');
38
+        if ($attivitaId <= 0 && ! auth()->user()?->hasRole('superadmin')) {
39
+            $attivitaId = -1;
40
+        }
38 41
         $attivita = Attivita::find($attivitaId);
39 42
         $period = $bilancioServizio->currentPeriod($attivitaId);
40 43
         $periodStart = $period['start'];
@@ -62,6 +65,9 @@ class BilancioController extends Controller
62 65
     public function index(Request $request, BilancioServizioService $bilancioServizio)
63 66
     {
64 67
         $attivitaId = (int) session()->get('attivita_attuale');
68
+        if ($attivitaId <= 0 && ! auth()->user()?->hasRole('superadmin')) {
69
+            $attivitaId = -1;
70
+        }
65 71
         $attivita = Attivita::find($attivitaId);
66 72
 
67 73
         $year = (int) $request->get('anno', now()->year);
@@ -82,12 +88,9 @@ class BilancioController extends Controller
82 88
             ->get();
83 89
 
84 90
         $movimenti = $movimentiCollection->map(function ($movimento) {
85
-            $tipoRaw = strtolower((string) ($movimento->tipo_movimento ?? ''));
86
-            $isUscita = $tipoRaw === 'uscita' || ((float) ($movimento->importo ?? 0)) < 0;
87
-
88 91
             return [
89 92
                 'data' => $movimento->created_at,
90
-                'tipo' => $isUscita ? 'uscita' : 'entrata',
93
+                'tipo' => $movimento->tipoPerAggregazione(),
91 94
                 'importo' => abs((float) ($movimento->importo ?? 0)),
92 95
                 'pagamento_id' => (int) ($movimento->pagamento_id ?? 0),
93 96
                 'fornitore_id' => (int) ($movimento->fornitore_id ?? 0),
@@ -105,6 +108,8 @@ class BilancioController extends Controller
105 108
 
106 109
         $ricaviTotali = (float) $movimenti->where('tipo', 'entrata')->sum('importo');
107 110
         $costiTotali = (float) $movimenti->where('tipo', 'uscita')->sum('importo');
111
+        $importoNonContabilizzato = (float) $movimenti->where('tipo', 'no_contabile')->sum('importo');
112
+        $movimentiNonContabilizzatiCount = (int) $movimenti->where('tipo', 'no_contabile')->count();
108 113
 
109 114
         // Fallback per ricavi se la prima nota non contiene entrate.
110 115
         $pagamentiCollection = Pagamento::query()
@@ -113,6 +118,7 @@ class BilancioController extends Controller
113 118
                 $query->where('attivita_id', $attivitaId);
114 119
             })
115 120
             ->whereBetween('created_at', [$yearStart, $yearEnd])
121
+            ->perIncasso()
116 122
             ->orderBy('created_at')
117 123
             ->get();
118 124
 
@@ -145,6 +151,9 @@ class BilancioController extends Controller
145 151
                 continue;
146 152
             }
147 153
             $row = $mesiBase->get($monthKey);
154
+            if ($movimento['tipo'] === 'no_contabile') {
155
+                continue;
156
+            }
148 157
             if ($movimento['tipo'] === 'entrata') {
149 158
                 $row['ricavi'] += $movimento['importo'];
150 159
             } else {
@@ -377,6 +386,8 @@ class BilancioController extends Controller
377 386
             'costiTotali' => $costiTotali,
378 387
             'saldoTotale' => $saldo,
379 388
             'movimentiCount' => $movimenti->count(),
389
+            'importoNonContabilizzato' => $importoNonContabilizzato,
390
+            'movimentiNonContabilizzatiCount' => $movimentiNonContabilizzatiCount,
380 391
             'andamentoMensile' => $andamentoMensile,
381 392
             'costiRows' => $costiRows,
382 393
             'ricaviRows' => $ricaviRows,

+ 114
- 72
app/Http/Controllers/CarrelloController.php Просмотреть файл

@@ -3,8 +3,9 @@
3 3
 namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6
+use Illuminate\Routing\Controllers\Middleware;
6 7
 use App\Models\Ordine;
7
-use App\Models\PuntoVendita;
8
+// use App\Models\PuntoVendita;
8 9
 use App\Models\Attivita;
9 10
 use App\Models\Dispositivo;
10 11
 use App\Models\Pagamento;
@@ -16,53 +17,72 @@ use Illuminate\Support\Facades\Auth;
16 17
 use Illuminate\Support\Facades\Session;
17 18
 use App\Http\Controllers\PagamentoController;
18 19
 use App\Services\Carrello\CarrelloService;
20
+use App\Services\Attivita\AttivitaService;
19 21
 
20 22
 class CarrelloController extends Controller
21 23
 {
22
-
23 24
     private CarrelloService $carrelloService;
24 25
 
26
+    public static function middleware(): array
27
+    {
28
+        return [
29
+            new Middleware('permission:view-punto_vendita', only: [
30
+                'index', 'list', 'totale', 'checkout',
31
+                'aumenta', 'diminuisci', 'elimina', 'aggiorna_nota', 'azzera',
32
+                'aggiungi_variante', 'elimina_variante', 'aggiorna_info', 'paga_ordine',
33
+            ]),
34
+        ];
35
+    }
36
+
25 37
     public function __construct(CarrelloService $carrelloService)
26 38
     {
27 39
         $this->carrelloService = $carrelloService;
28 40
     }
29 41
 
30
-    public function index(){
31
-        // return Ordine::all();
32
-        return Ordine::where('stato', Ordine::CARRELLO)->get();
33
-    }
42
+    public function index()
43
+    {
44
+        [$attivitaId, $dispositivoId] = $this->carrelloService->contestoCassa();
34 45
 
46
+        return Ordine::where('stato', Ordine::CARRELLO)
47
+            ->where('attivita_id', $attivitaId)
48
+            ->where('dispositivo_id', $dispositivoId)
49
+            ->get();
50
+    }
35 51
 
36
-    public function list(Request $request, RigaOrdineDataTable $dataTable){
52
+    public function list(Request $request, RigaOrdineDataTable $dataTable)
53
+    {
54
+        [$attivitaId, $dispositivoId] = $this->carrelloService->contestoCassa();
37 55
         $ordine = Ordine::where([
38
-            'stato' => Ordine::CARRELLO, 
39
-            'dispositivo_id' => Session::get('dispositivo_id') || $request->dispositivo_id,
40
-            'attivita_id' => Session::get('attivita_id') || $request->attivita_id,
56
+            'stato' => Ordine::CARRELLO,
57
+            'dispositivo_id' => $dispositivoId,
58
+            'attivita_id' => $attivitaId,
41 59
         ])->orderBy('created_at', 'desc')->first();
42
-    // dd($ordine->count());
60
+
43 61
         return $dataTable->render('punto_vendita.cassa._partials.carrello.index', ['ordine' => $ordine]);
44 62
     }
45 63
 
46
-
47
-    public function aumenta(Request $request){
64
+    public function aumenta(Request $request)
65
+    {
48 66
         $request->validate([
49 67
             'ordine_id' => 'nullable|integer',
50 68
             'piatto_id' => 'required|integer|exists:piatto,id',
51
-            'dispositivo_id' => 'required|integer|exists:dispositivo,id',
52
-            'attivita_id' => 'nullable|integer|exists:attivita,id',
53 69
             'riga_ordine_id' => 'nullable|integer|exists:riga_ordine,id',
54 70
         ]);
55
-       
56
-       $result = $this->carrelloService->aumentaQuantita($request->dispositivo_id, $request->attivita_id, $request->ordine_id, $request->piatto_id, $request->riga_ordine_id);
57
-       $carrello = $result['ordine'];
58
-       $riga = $result['riga'];
59 71
 
60
-       return response()->json([
61
-           'success' => true,
62
-           'message' => 'Quantità aumentata',
63
-           'ordine_id' => $carrello->id,
64
-           'data' => $riga,
65
-       ]);
72
+        $result = $this->carrelloService->aumentaQuantita(
73
+            $request->filled('ordine_id') ? (int) $request->ordine_id : null,
74
+            (int) $request->piatto_id,
75
+            $request->filled('riga_ordine_id') ? (int) $request->riga_ordine_id : null
76
+        );
77
+        $carrello = $result['ordine'];
78
+        $riga = $result['riga'];
79
+
80
+        return response()->json([
81
+            'success' => true,
82
+            'message' => 'Quantità aumentata',
83
+            'ordine_id' => $carrello->id,
84
+            'data' => $riga,
85
+        ]);
66 86
 
67 87
 
68 88
         // Tolleranza su ordine_id stale: se non e` valido, usa/crea il carrello corrente per dispositivo+attivita.
@@ -278,9 +298,9 @@ class CarrelloController extends Controller
278 298
         // // }
279 299
     }
280 300
 
281
-    public function totale(Request $request){
282
-        $ordine = Ordine::find($request->ordine_id);
283
-        if ($ordine == null){ 
301
+    public function totale(Request $request)
302
+    {
303
+        if (! $request->filled('ordine_id')) {
284 304
             return response()->json([
285 305
                 'success' => true,
286 306
                 'message' => 'Totale carrello',
@@ -289,6 +309,8 @@ class CarrelloController extends Controller
289 309
                 'quantita_totale' => 0,
290 310
             ]);
291 311
         }
312
+
313
+        $ordine = $this->carrelloService->carrelloDiQuestaCassa((int) $request->ordine_id);
292 314
         // dd([$ordine->prezzo , $request->all()]);
293 315
         if($ordine->prezzo == null || $ordine->prezzo == 0){
294 316
             if($ordine->righe_ordine->count() >0){
@@ -310,15 +332,12 @@ class CarrelloController extends Controller
310 332
             'quantita_totale' => $quantitaTotale,
311 333
         ]);
312 334
     }
313
-    public function aggiorna_info(Request $request){
314
-        $ordine = Ordine::find($request->ordine_id);
315
-        if($ordine == null){
316
-            return response()->json([
317
-                'success' => false,
318
-                'message' => 'Ordine non trovato',
319
-                'data' => null,
320
-            ]);
321
-        }
335
+    public function aggiorna_info(Request $request)
336
+    {
337
+        $request->validate([
338
+            'ordine_id' => 'required|integer',
339
+        ]);
340
+        $ordine = $this->carrelloService->carrelloDiQuestaCassa((int) $request->ordine_id);
322 341
         $info = is_array($ordine->info) ? $ordine->info : [];
323 342
         $info['cliente'] = $request->cliente;
324 343
         $info['tavolo'] = $request->tavolo;
@@ -333,23 +352,9 @@ class CarrelloController extends Controller
333 352
     }
334 353
 
335 354
 
336
-    public function checkout(Request $request){
337
-        // $ordineA = Ordine::where([
338
-        //     'stato' => Ordine::CARRELLO, 
339
-        //     // 'dispositivo_id' => Session::get('dispositivo_id') || $request->dispositivo_id,
340
-        //     'attivita_id' => Session::get('attivita_id') || $request->attivita_id,
341
-        // ])->orderBy('created_at', 'desc')->first();
342
-        $ordine = Ordine::find($request->ordine_id);
343
-        if($ordine == null){
344
-            return  response()->json([
345
-                'success' => false,
346
-                'message' => 'Ordine non trovato',
347
-                'data' => null,
348
-                'ordineA' => $ordineA,
349
-                'ordineB' => $ordineB,
350
-                // 'ordineA->id == ordineB->id' => $ordineA->id == $ordineB->id,
351
-            ]);
352
-        }
355
+    public function checkout(Request $request)
356
+    {
357
+        $ordine = $this->carrelloService->carrelloDiQuestaCassa((int) $request->ordine_id);
353 358
 
354 359
         $ordine->prezzo = $ordine->righe_ordine->sum('prezzo');
355 360
         // $ordine->stato = Ordine::CHECKOUT;
@@ -361,22 +366,34 @@ class CarrelloController extends Controller
361 366
     }
362 367
 
363 368
     public function paga_ordine(Request $request){
369
+
364 370
         
365
-        if(!$request->filled('tag_id') && MetodoPagamento::find($request->metodo_pagamento_id)->tipo == MetodoPagamento::SEGRESTA_WALLET){
366
-            return back()->with('error', 'Tag ID obbligatorio per il metodo di pagamento Segresta Wallet');
371
+        $ordine = $this->carrelloService->carrelloDiQuestaCassa((int) $request->ordine_id);
372
+
373
+        $attivitaId = (int) (session('attivita_attuale') ?: session('attivita_id'));
374
+        $dispositivoId = (int) session('dispositivo_id');
375
+
376
+
377
+        if ($ordine->stato !== Ordine::CARRELLO) {
378
+            return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id , 'vista' => $request->vista])->with('error', 'Questo ordine non è più un carrello');
367 379
         }
368
-        
369
-        $ordine = Ordine::find($request->ordine_id);
370
-        if($ordine == null){
371
-            return response()->json([
372
-                'success' => false,
373
-                'message' => 'Ordine non trovato',
374
-                'data' => null,
375
-            ]);
380
+
381
+        $metodo = MetodoPagamento::where('id', $request->metodo_pagamento_id)
382
+                ->where('attivita_id', $attivitaId)
383
+                ->where('is_attivo', true)
384
+                ->first();
385
+        if (! $metodo) {
386
+            return back()->with('error', 'Metodo di pagamento non valido');
387
+        }
388
+
389
+                
390
+        if(!$request->filled('tag_id') && $metodo->tipo == MetodoPagamento::SEGRESTA_WALLET){
391
+            return back()->with('error', 'Tag ID obbligatorio per il metodo di pagamento Segresta Wallet');
376 392
         }
393
+
377 394
         $pagamento = Pagamento::create([
378
-            'attivita_id' => session('attivita_id'), //$request->attivita_id,
379
-            'dispositivo_id' => $request->dispositivo_id,
395
+            'attivita_id' => $attivitaId,
396
+            'dispositivo_id' => $dispositivoId,
380 397
             'ordine_id' => $ordine->id,
381 398
             'metodo_pagamento_id' => $request->metodo_pagamento_id,
382 399
             'tipo' => $request->tipo,
@@ -406,6 +423,9 @@ class CarrelloController extends Controller
406 423
                     $ordine->update(['stato' => Ordine::PAGATO]);
407 424
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id , 'vista' => $request->vista])->with('success', 'Pagamento con contanti riuscito. ->'.$pagamento->metodo_pagamento->tipo);
408 425
                 }else{
426
+                    $pagamento->stato = Pagamento::ERRORE;
427
+                    $pagamento->save();
428
+
409 429
                     $ordine->stato = Ordine::CARRELLO;
410 430
                     $ordine->save();
411 431
                     return back()->with('error', 'Pagamento con contanti non riuscito. '.$pagamentoResult['message']);
@@ -417,6 +437,9 @@ class CarrelloController extends Controller
417 437
                 // $pagamento->save();
418 438
                 // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con bonifico riuscito.');
419 439
                 
440
+                $pagamento->stato = Pagamento::ERRORE;
441
+                $pagamento->save();
442
+
420 443
                 $ordine->stato = Ordine::CARRELLO;
421 444
                     $ordine->save();
422 445
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
@@ -426,7 +449,9 @@ class CarrelloController extends Controller
426 449
                 // $pagamento->update(['stato' , Pagamento::PAGATO]);
427 450
                 // $pagamento->save();
428 451
                 // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con paypal riuscito.');
429
-                
452
+                $pagamento->stato = Pagamento::ERRORE;
453
+                $pagamento->save();
454
+
430 455
                 $ordine->stato = Ordine::CARRELLO;
431 456
                     $ordine->save();
432 457
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
@@ -436,19 +461,24 @@ class CarrelloController extends Controller
436 461
                 // $pagamento->update(['stato' , Pagamento::PAGATO]);
437 462
                 // $pagamento->save();
438 463
                 // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con carta di debito riuscito.');
439
-                
464
+                $pagamento->stato = Pagamento::ERRORE;
465
+                $pagamento->save();
466
+
440 467
                 $ordine->stato = Ordine::CARRELLO;
441 468
                     $ordine->save();
442 469
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
443 470
 
444 471
                 break;
445 472
             case MetodoPagamento::CUPON:
446
-                $pagamentoResult = app('\App\Services\Paga\Cupon')->paga($pagamento);
473
+                $pagamentoResult = app('\App\Services\Paga\PagaCupon')->paga($pagamento, $request->cupon_codice);
447 474
                 
448 475
                 if($pagamentoResult['result'] === true){
449 476
                     $ordine->update(['stato' => Ordine::PAGATO]);
450 477
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con cupon riuscito.');
451 478
                 }else{
479
+                    $pagamento->stato = Pagamento::ERRORE;
480
+                    $pagamento->save();
481
+
452 482
                     $ordine->stato = Ordine::CARRELLO;
453 483
                     $ordine->save();
454 484
                     return back()->with('error', 'Pagamento con cupon non riuscito. '.$pagamentoResult['message']);
@@ -460,7 +490,8 @@ class CarrelloController extends Controller
460 490
                 
461 491
                 if($pagamentoResult['result'] === true){
462 492
                     $pagamento->update(['stato' => Pagamento::PAGATO]);
463
-                    $pagamento->save();
493
+                    $ordine->update(['stato' => Ordine::PAGATO]);
494
+
464 495
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con wallet riuscito.');
465 496
                 }else{
466 497
                     $pagamento->stato = Pagamento::ERRORE;
@@ -475,7 +506,9 @@ class CarrelloController extends Controller
475 506
                     // $pagamento->update(['stato' , Pagamento::PAGATO]);
476 507
                     // $pagamento->save();
477 508
                     // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con apple pay riuscito.');
478
-                    
509
+                    $pagamento->stato = Pagamento::ERRORE;
510
+                    $pagamento->save();
511
+
479 512
                     $ordine->stato = Ordine::CARRELLO;
480 513
                     $ordine->save();
481 514
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
@@ -485,7 +518,9 @@ class CarrelloController extends Controller
485 518
                 // $pagamento->update(['stato' , Pagamento::PAGATO]);
486 519
                 // $pagamento->save();
487 520
                 // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con google pay riuscito.');
488
-                
521
+                $pagamento->stato = Pagamento::ERRORE;
522
+                $pagamento->save();
523
+
489 524
                 $ordine->stato = Ordine::CARRELLO;
490 525
                     $ordine->save();
491 526
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
@@ -498,10 +533,14 @@ class CarrelloController extends Controller
498 533
                     $ordine->update(['stato' => Ordine::PAGATO]);
499 534
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con contanti riuscito. ->'.$pagamento->metodo_pagamento->tipo);
500 535
                 }else{
536
+                    $pagamento->stato = Pagamento::ERRORE;
537
+                    $pagamento->save();
538
+
501 539
                     $ordine->stato = Ordine::CARRELLO;
502 540
                     $ordine->save();
503 541
                     return back()->with('error', 'Pagamento con contanti non riuscito. '.$pagamentoResult['message']);
504 542
                 }
543
+                break;
505 544
 
506 545
             case MetodoPagamento::STAFF:
507 546
                 $pagamentoResult = app('\App\Services\Paga\Staff')->paga($pagamento);
@@ -510,6 +549,9 @@ class CarrelloController extends Controller
510 549
                     $ordine->update(['stato' => Ordine::PAGATO]);
511 550
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con staff riuscito.');
512 551
                 }else{
552
+                    $pagamento->stato = Pagamento::ERRORE;
553
+                    $pagamento->save();
554
+
513 555
                     $ordine->stato = Ordine::CARRELLO;
514 556
                     $ordine->save();
515 557
                     return back()->with('error', 'Pagamento con staff non riuscito. '.$pagamentoResult['message']);

+ 2
- 0
app/Http/Controllers/CategoriaContabileController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Categoriacontabile;
7 9
 use App\DataTables\CategoriacontabileDataTable;

+ 3
- 1
app/Http/Controllers/ChiusuraServizioController.php Просмотреть файл

@@ -12,6 +12,7 @@ use Carbon\Carbon;
12 12
 use Illuminate\Routing\Controllers\Middleware;
13 13
 use Illuminate\Support\Facades\Auth;
14 14
 use Illuminate\Support\Facades\Session;
15
+use App\Services\Attivita\AttivitaService;
15 16
 
16 17
 class ChiusuraServizioController extends Controller
17 18
 {
@@ -101,7 +102,8 @@ class ChiusuraServizioController extends Controller
101 102
       return redirect()->back()->with('error', 'Non autorizzato');
102 103
     }
103 104
 
104
-    $attivitaId = (int) ($request->input('attivita_id') ?: Session::get('attivita_attuale'));
105
+    $attivitaId = (int) Session::get('attivita_attuale');
106
+    AttivitaService::garantisciAttivita($attivitaId);
105 107
     $attivita = Attivita::find($attivitaId);
106 108
     if (!$attivita) {
107 109
       return redirect()->back()->with('error', 'Attività non trovata');

+ 380
- 18
app/Http/Controllers/ConsultaController.php Просмотреть файл

@@ -2,12 +2,18 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+use App\Models\EventoForm;
5 6
 use App\Models\Ordine;
6 7
 use App\Models\Prenotazione;
8
+use App\Models\PrenotazioneRisposta;
9
+use App\Notifications\PrenotazioneLinkModifica;
10
+use App\Services\Prenotazione\AccessoModificaCliente;
7 11
 use Endroid\QrCode\Builder\Builder;
8 12
 use Endroid\QrCode\Color\Color;
9 13
 use Endroid\QrCode\Writer\SvgWriter;
10 14
 use Illuminate\Http\Request;
15
+use Illuminate\Support\Facades\Notification;
16
+use Illuminate\Support\Facades\Validator;
11 17
 
12 18
 class ConsultaController extends Controller
13 19
 {
@@ -18,37 +24,400 @@ class ConsultaController extends Controller
18 24
 
19 25
     public function scontrino_show(Request $request)
20 26
     {
21
-        $ordine = Ordine::find($request->route('ordine_id'));
22
-        // dd($ordine);
23
-        if (!$ordine) {
27
+        $ordine = Ordine::where('codice', $request->route('ordine_codice'))->first();
28
+        if (! $ordine) {
24 29
             return redirect()->route('consulta.index')->with('error', 'Ordine non trovato');
25 30
         }
31
+
26 32
         return view('consulta.scontrino.show', compact('ordine'));
27 33
     }
28
-    
34
+
29 35
     public function comanda_show(Request $request)
30 36
     {
31
-        $ordine = Ordine::find($request->route('ordine_id'));
32
-        if (!$ordine) {
37
+        $ordine = Ordine::where('codice', $request->route('ordine_codice'))->first();
38
+        if (! $ordine) {
33 39
             return redirect()->route('consulta.index')->with('error', 'Ordine non trovato');
34 40
         }
41
+
35 42
         return view('consulta.comanda.show', compact('ordine'));
36 43
     }
44
+
37 45
     public function prenotazione_show(Request $request)
38 46
     {
47
+        $prenotazione = $this->trovaPrenotazionePerCodice($request->route('codice'));
48
+        if (! $prenotazione) {
49
+            return redirect()->route('welcome')->with('error', 'Prenotazione non trovata');
50
+        }
51
+
52
+        return view('consulta.prenotazione.show', [
53
+            'prenotazione' => $prenotazione,
54
+            'codiceQrSvg' => $this->qrSvg($prenotazione),
55
+            'puoModificare' => (bool) $prenotazione->evento?->clientePuoModificareQuestaPrenotazione($prenotazione),
56
+            'puoAnnullare' => (bool) $prenotazione->evento?->clientePuoAnnullareQuestaPrenotazione($prenotazione),
57
+        ]);
58
+    }
59
+
60
+    public function prenotazione_calendario(Request $request, \App\Services\Calendario\CreaIcsPrenotazione $ics)
61
+    {
62
+        $request->validate([
63
+            'codice' => 'required|string',
64
+        ]);
65
+
39 66
         $prenotazione = Prenotazione::query()
67
+            ->with(['evento.attivita'])
68
+            ->where('codice', $request->get('codice'))
69
+            ->first();
70
+
71
+        if (! $prenotazione) {
72
+            return redirect()->route('consulta.index')->with('error', 'Prenotazione non trovata');
73
+        }
74
+
75
+        $contenuto = $ics->contenuto($prenotazione);
76
+        if (! $contenuto) {
77
+            return redirect()
78
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
79
+                ->with('error', 'Calendario non disponibile per questa prenotazione');
80
+        }
81
+
82
+        return response($contenuto, 200, [
83
+            'Content-Type' => 'text/calendar; charset=utf-8',
84
+            'Content-Disposition' => 'attachment; filename="'.$ics->nomeFile($prenotazione).'"',
85
+        ]);
86
+    }
87
+
88
+    /**
89
+     * Da consulta: invia email con magic link (modifica o annulla).
90
+     */
91
+    public function prenotazione_richiedi_modifica(Request $request, AccessoModificaCliente $accesso)
92
+    {
93
+        $data = $request->validate([
94
+            'codice' => 'required|string',
95
+            'azione' => 'required|in:modifica,annulla',
96
+        ]);
97
+
98
+        $prenotazione = $this->trovaPrenotazionePerCodice($data['codice']);
99
+        if (! $prenotazione) {
100
+            return redirect()->route('consulta.index')->with('error', 'Prenotazione non trovata');
101
+        }
102
+
103
+        $azione = $data['azione'];
104
+        if (! $accesso->puoRichiedereLink($prenotazione, $azione)) {
105
+            return redirect()
106
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
107
+                ->with('error', 'Questa operazione non è più disponibile per la prenotazione.');
108
+        }
109
+
110
+        if (! filled($prenotazione->email)) {
111
+            return redirect()
112
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
113
+                ->with('error', 'Nessuna email associata a questa prenotazione.');
114
+        }
115
+
116
+        if (! $accesso->puoInviareOra($prenotazione, $azione)) {
117
+            return redirect()
118
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
119
+                ->with('error', 'Abbiamo già inviato un link. Controlla la posta o riprova tra un minuto.');
120
+        }
121
+
122
+        $url = $accesso->urlFirmato($prenotazione, $azione);
123
+        $emailMask = $accesso->mascheraEmail($prenotazione->email);
124
+
125
+        Notification::route('mail', $prenotazione->email)
126
+            ->notify(new PrenotazioneLinkModifica($prenotazione, $azione, $url));
127
+
128
+        $msg = $azione === 'annulla'
129
+            ? 'Ti abbiamo inviato un’email a '.$emailMask.' con il link per annullare (valido '.AccessoModificaCliente::MINUTI_LINK.' minuti). Controlla anche lo spam.'
130
+            : 'Ti abbiamo inviato un’email a '.$emailMask.' con il link per modificare (valido '.AccessoModificaCliente::MINUTI_LINK.' minuti). Controlla anche lo spam.';
131
+
132
+        return redirect()
133
+            ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
134
+            ->with('success', $msg);
135
+    }
136
+
137
+    /**
138
+     * Entrypoint magic link firmato (monouso) → avvia sessione 15 min.
139
+     */
140
+    public function prenotazione_modifica_apri(Request $request, AccessoModificaCliente $accesso)
141
+    {
142
+        if (! $request->hasValidSignature()) {
143
+            return redirect()
144
+                ->route('consulta.index')
145
+                ->with('error', 'Link non valido o scaduto. Richiedine uno nuovo dalla scheda prenotazione.');
146
+        }
147
+
148
+        $codice = (string) $request->query('codice', '');
149
+        $azione = (string) $request->query('azione', 'modifica');
150
+
151
+        $prenotazione = $this->trovaPrenotazionePerCodice($codice);
152
+        if (! $prenotazione) {
153
+            return redirect()->route('consulta.index')->with('error', 'Prenotazione non trovata');
154
+        }
155
+
156
+        if (! $accesso->puoRichiedereLink($prenotazione, $azione)) {
157
+            return redirect()
158
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
159
+                ->with('error', 'Questa operazione non è più disponibile.');
160
+        }
161
+
162
+        if (! $accesso->consumaLink($request)) {
163
+            return redirect()
164
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
165
+                ->with('error', 'Questo link è già stato usato. Richiedine uno nuovo se serve.');
166
+        }
167
+
168
+        $accesso->avviaSessione($prenotazione, $azione);
169
+
170
+        return $azione === 'annulla'
171
+            ? redirect()->route('consulta.prenotazione.annulla.form')
172
+            : redirect()->route('consulta.prenotazione.modifica.form');
173
+    }
174
+
175
+    public function prenotazione_modifica_form(AccessoModificaCliente $accesso)
176
+    {
177
+        $prenotazione = $this->prenotazioneDaSessione($accesso, 'modifica');
178
+        if (! $prenotazione) {
179
+            return redirect()->route('consulta.index')->with('error', 'Sessione di modifica scaduta. Richiedi un nuovo link.');
180
+        }
181
+
182
+        if (! $accesso->puoRichiedereLink($prenotazione, 'modifica')) {
183
+            $accesso->chiudiSessione();
184
+
185
+            return redirect()
186
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
187
+                ->with('error', 'La modifica non è più disponibile.');
188
+        }
189
+
190
+        $risposte = $this->rispostePerForm($prenotazione);
191
+
192
+        return view('consulta.prenotazione.modifica', [
193
+            'prenotazione' => $prenotazione,
194
+            'evento' => $prenotazione->evento,
195
+            'risposte' => $risposte,
196
+            'minutiSessione' => AccessoModificaCliente::MINUTI_LINK,
197
+        ]);
198
+    }
199
+
200
+    public function prenotazione_modifica_salva(Request $request, AccessoModificaCliente $accesso)
201
+    {
202
+        $prenotazione = $this->prenotazioneDaSessione($accesso, 'modifica');
203
+        if (! $prenotazione || ! $prenotazione->evento) {
204
+            return redirect()->route('consulta.index')->with('error', 'Sessione di modifica scaduta.');
205
+        }
206
+
207
+        $evento = $prenotazione->evento;
208
+        if (! $accesso->puoRichiedereLink($prenotazione, 'modifica')) {
209
+            $accesso->chiudiSessione();
210
+
211
+            return redirect()
212
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
213
+                ->with('error', 'La modifica non è più disponibile.');
214
+        }
215
+
216
+        $nPersone = max(1, (int) $request->input('numero_persone', 1));
217
+        $user = null;
218
+
219
+        $rules = [
220
+            'nome' => 'required|string|max:255',
221
+            'cognome' => 'required|string|max:255',
222
+            'telefono' => 'nullable|string|max:50',
223
+            'note' => 'nullable|string|max:2000',
224
+            'numero_persone' => 'required|integer|min:1|max:100',
225
+        ];
226
+
227
+        $campiVisibili = $evento->form->filter(fn ($campo) => $campo->isVisibileAlCliente($user));
228
+
229
+        foreach ($campiVisibili as $campo) {
230
+            $key = 'prenotazione_risposta_'.$campo->id;
231
+            $obbligatoria = (bool) $campo->obbligatoria;
232
+
233
+            if ($campo->per_coperto) {
234
+                $rules[$key] = $obbligatoria ? 'required|array|size:'.$nPersone : 'nullable|array';
235
+                for ($i = 0; $i < $nPersone; $i++) {
236
+                    if ($campo->tipo === EventoForm::MULTISELEZIONE) {
237
+                        $rules[$key.'.'.$i] = $obbligatoria ? 'required|array|min:1' : 'nullable|array';
238
+                    } elseif ($campo->tipo === EventoForm::CHECKBOX) {
239
+                        $rules[$key.'.'.$i] = $obbligatoria ? 'required|in:1' : 'nullable';
240
+                    } else {
241
+                        $rules[$key.'.'.$i] = $obbligatoria ? 'required' : 'nullable';
242
+                    }
243
+                }
244
+            } elseif ($campo->tipo === EventoForm::MULTISELEZIONE) {
245
+                $rules[$key] = $obbligatoria ? 'required|array|min:1' : 'nullable|array';
246
+            } elseif ($campo->tipo === EventoForm::CHECKBOX) {
247
+                $rules[$key] = $obbligatoria ? 'required|in:1' : 'nullable';
248
+            } else {
249
+                $rules[$key] = $obbligatoria ? 'required' : 'nullable';
250
+            }
251
+        }
252
+
253
+        $validator = Validator::make($request->all(), $rules);
254
+        if ($validator->fails()) {
255
+            return redirect()
256
+                ->route('consulta.prenotazione.modifica.form')
257
+                ->withErrors($validator)
258
+                ->withInput()
259
+                ->with('error', $validator->errors()->first());
260
+        }
261
+
262
+        $eraConfermata = $prenotazione->stato === Prenotazione::STATO_CONFERMATA
263
+            || (bool) $prenotazione->confermata;
264
+
265
+        $prenotazione->fill($request->only(['nome', 'cognome', 'telefono', 'note']));
266
+        $prenotazione->numero_persone = $nPersone;
267
+        // Email non modificabile dal cliente.
268
+
269
+        if ($eraConfermata && $evento->clienteModificaSeConfermata()) {
270
+            $prenotazione->stato = Prenotazione::STATO_INVIATA;
271
+            $prenotazione->confermata = false;
272
+        }
273
+
274
+        $prenotazione->save();
275
+
276
+        $seenFormIds = [];
277
+        foreach ($campiVisibili as $campo) {
278
+            $value = $request->input('prenotazione_risposta_'.$campo->id);
279
+            if (is_array($value)) {
280
+                $value = json_encode(array_values($value), JSON_UNESCAPED_UNICODE);
281
+            }
282
+
283
+            if ($value === null || $value === '') {
284
+                continue;
285
+            }
286
+
287
+            PrenotazioneRisposta::updateOrCreate(
288
+                [
289
+                    'prenotazione_id' => $prenotazione->id,
290
+                    'evento_form_id' => $campo->id,
291
+                ],
292
+                ['risposta' => (string) $value]
293
+            );
294
+            $seenFormIds[] = $campo->id;
295
+        }
296
+
297
+        $visibleIds = $campiVisibili->pluck('id')->all();
298
+        if ($visibleIds !== []) {
299
+            $prenotazione->risposte()
300
+                ->whereIn('evento_form_id', $visibleIds)
301
+                ->when(
302
+                    $seenFormIds !== [],
303
+                    fn ($q) => $q->whereNotIn('evento_form_id', $seenFormIds),
304
+                    fn ($q) => $q
305
+                )
306
+                ->delete();
307
+        }
308
+
309
+        $accesso->chiudiSessione();
310
+
311
+        $msg = 'Prenotazione aggiornata.';
312
+        if ($eraConfermata && $prenotazione->stato === Prenotazione::STATO_INVIATA) {
313
+            $msg .= ' È tornata in attesa di conferma da parte degli organizzatori.';
314
+        }
315
+
316
+        return redirect()
317
+            ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
318
+            ->with('success', $msg);
319
+    }
320
+
321
+    public function prenotazione_annulla_form(AccessoModificaCliente $accesso)
322
+    {
323
+        $prenotazione = $this->prenotazioneDaSessione($accesso, 'annulla');
324
+        if (! $prenotazione) {
325
+            return redirect()->route('consulta.index')->with('error', 'Sessione scaduta. Richiedi un nuovo link.');
326
+        }
327
+
328
+        if (! $accesso->puoRichiedereLink($prenotazione, 'annulla')) {
329
+            $accesso->chiudiSessione();
330
+
331
+            return redirect()
332
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
333
+                ->with('error', 'L’annullamento non è più disponibile.');
334
+        }
335
+
336
+        return view('consulta.prenotazione.annulla', [
337
+            'prenotazione' => $prenotazione,
338
+            'evento' => $prenotazione->evento,
339
+            'minutiSessione' => AccessoModificaCliente::MINUTI_LINK,
340
+        ]);
341
+    }
342
+
343
+    public function prenotazione_annulla_conferma(Request $request, AccessoModificaCliente $accesso)
344
+    {
345
+        $prenotazione = $this->prenotazioneDaSessione($accesso, 'annulla');
346
+        if (! $prenotazione) {
347
+            return redirect()->route('consulta.index')->with('error', 'Sessione scaduta.');
348
+        }
349
+
350
+        if (! $accesso->puoRichiedereLink($prenotazione, 'annulla')) {
351
+            $accesso->chiudiSessione();
352
+
353
+            return redirect()
354
+                ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
355
+                ->with('error', 'L’annullamento non è più disponibile.');
356
+        }
357
+
358
+        $request->validate([
359
+            'conferma' => 'accepted',
360
+        ], [
361
+            'conferma.accepted' => 'Conferma di voler annullare la prenotazione.',
362
+        ]);
363
+
364
+        $prenotazione->stato = Prenotazione::STATO_CANCELLATA;
365
+        $prenotazione->confermata = false;
366
+        $prenotazione->save();
367
+
368
+        $accesso->chiudiSessione();
369
+
370
+        return redirect()
371
+            ->route('consulta.prenotazione.show', ['codice' => $prenotazione->codice])
372
+            ->with('success', 'Prenotazione annullata.');
373
+    }
374
+
375
+    private function trovaPrenotazionePerCodice(?string $codice): ?Prenotazione
376
+    {
377
+        if (! filled($codice)) {
378
+            return null;
379
+        }
380
+
381
+        return Prenotazione::query()
40 382
             ->with([
41 383
                 'risposte',
384
+                'evento.attivita',
42 385
                 'evento.form' => function ($q) {
43
-                    $q->orderBy('ordine_visualizzazione')->with('opzioni_form');
386
+                    $q->orderBy('ordine_visualizzazione')->with(['opzioni_form' => function ($oq) {
387
+                        $oq->orderBy('ordine')->orderBy('id');
388
+                    }]);
44 389
                 },
45 390
             ])
46
-            ->where('codice', $request->get('codice'))
391
+            ->where('codice', $codice)
47 392
             ->first();
48
-        if (!$prenotazione) {
49
-            return redirect()->route('consulta.index')->with('error', 'Prenotazione non trovata');
393
+    }
394
+
395
+    private function prenotazioneDaSessione(AccessoModificaCliente $accesso, string $azione): ?Prenotazione
396
+    {
397
+        if (! $accesso->sessioneValida(azione: $azione)) {
398
+            return null;
50 399
         }
51 400
 
401
+        $codice = $accesso->codiceSessione();
402
+
403
+        return $this->trovaPrenotazionePerCodice($codice);
404
+    }
405
+
406
+    private function rispostePerForm(Prenotazione $prenotazione): array
407
+    {
408
+        $risposte = [];
409
+        foreach ($prenotazione->risposte as $r) {
410
+            $decoded = json_decode((string) $r->risposta, true);
411
+            $risposte[$r->evento_form_id] = (json_last_error() === JSON_ERROR_NONE && is_array($decoded))
412
+                ? $decoded
413
+                : $r->risposta;
414
+        }
415
+
416
+        return $risposte;
417
+    }
418
+
419
+    private function qrSvg(Prenotazione $prenotazione): string
420
+    {
52 421
         $qrBuilder = new Builder(
53 422
             writer: new SvgWriter(),
54 423
             writerOptions: [
@@ -56,18 +425,11 @@ class ConsultaController extends Controller
56 425
             ],
57 426
         );
58 427
 
59
-        $codiceQrSvg = $qrBuilder->build(
428
+        return $qrBuilder->build(
60 429
             data: (string) $prenotazione->codice,
61 430
             size: 168,
62 431
             margin: 4,
63 432
             foregroundColor: new Color(21, 38, 92),
64
-            // class: 'bg-primary',
65
-            // backgroundColor: new Color(245, 130, 32),
66 433
         )->getString();
67
-
68
-        return view('consulta.prenotazione.show', [
69
-            'prenotazione' => $prenotazione,
70
-            'codiceQrSvg' => $codiceQrSvg,
71
-        ]);
72 434
     }
73 435
 }

+ 7
- 0
app/Http/Controllers/ContenutoBachecaController.php Просмотреть файл

@@ -2,12 +2,15 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\ContenutoBacheca;
7 9
 use App\DataTables\ContenutoBachecaDataTable;
8 10
 use App\DataTables\ContenutoBachecaDataTableEditor;
9 11
 use Illuminate\Support\Facades\Auth;
10 12
 use Illuminate\Support\Facades\Session;
13
+use App\Services\Attivita\AttivitaService;
11 14
 
12 15
 class ContenutoBachecaController extends Controller
13 16
 {
@@ -56,6 +59,10 @@ class ContenutoBachecaController extends Controller
56 59
     public function show(Request $request)
57 60
     {
58 61
         $contenuto_bacheca = ContenutoBacheca::find($request->get('contenuto_bacheca_id'));
62
+        if (! $contenuto_bacheca) {
63
+            abort(404);
64
+        }
65
+        AttivitaService::garantisciAttivita($contenuto_bacheca->attivita_id);
59 66
         return view('contenuto_bacheca.show', ['contenuto_bacheca' => $contenuto_bacheca]);
60 67
     }
61 68
     

+ 14
- 3
app/Http/Controllers/Controller.php Просмотреть файл

@@ -2,7 +2,18 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
-abstract class Controller
5
+use Illuminate\Routing\Controllers\HasMiddleware;
6
+
7
+abstract class Controller implements HasMiddleware
6 8
 {
7
-  //
8
-}
9
+    /**
10
+     * Laravel 12 applica il middleware dei controller solo se la classe
11
+     * implementa HasMiddleware. I figli possono sovrascrivere questo metodo.
12
+     *
13
+     * @return array<int, \Illuminate\Routing\Controllers\Middleware|\Closure|string>
14
+     */
15
+    public static function middleware(): array
16
+    {
17
+        return [];
18
+    }
19
+}

+ 3
- 1
app/Http/Controllers/CucinaController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Cucina;
7 9
 use App\DataTables\CucinaDataTable;
@@ -23,7 +25,7 @@ class CucinaController extends Controller
23 25
     public static function middleware(): array
24 26
     {
25 27
         return [
26
-            new Middleware('permission:view-cucina', only: ['index']),
28
+            new Middleware('permission:view-cucina', only: ['index', 'dashboard']),
27 29
             new Middleware('permission:create-cucina|edit-cucina|delete-cucina', only: ['store', 'update', 'destroy']),
28 30
         ];
29 31
     }

+ 395
- 0
app/Http/Controllers/CuponController.php Просмотреть файл

@@ -0,0 +1,395 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
7
+use Illuminate\Http\Request;
8
+use App\Models\Cupon;
9
+use App\DataTables\CuponDataTable;
10
+use App\DataTables\CuponDataTableEditor;
11
+use Illuminate\Support\Facades\Auth;
12
+use Illuminate\Support\Facades\Session;
13
+use Illuminate\Support\Facades\Storage;
14
+use Barryvdh\DomPDF\Facade\Pdf;
15
+use Illuminate\Support\Str;
16
+use App\Models\Attivita;
17
+use App\Models\Dispositivo;
18
+use App\Models\PrintJob;
19
+use App\Jobs\ElaboraJobStampa;
20
+use App\Services\Attivita\AttivitaService;
21
+use App\Models\Ordine;
22
+use Carbon\Carbon;
23
+
24
+class CuponController extends Controller
25
+{
26
+
27
+    public static $permission_group = "Cupon";
28
+    public static $permissions = [
29
+        'view-cupon' => 'Vedi',
30
+        'create-cupon' => 'Crea',
31
+        'edit-cupon' => 'Modifica',
32
+        'delete-cupon' => 'Elimina',
33
+    ];
34
+     
35
+    public static function middleware(): array
36
+    {
37
+        return [
38
+            new Middleware('permission:view-cupon', only: ['index', 'stampaCupon', 'pdfCupon', 'pdfCuponPersonalizzato', 'checklistCupon']),
39
+            new Middleware('permission:view-cupon|view-punto_vendita', only: ['check']),
40
+            new Middleware('permission:create-cupon|edit-cupon|delete-cupon', only: ['store', 'update', 'destroy', 'generaBatch', 'uploadCuponTemplate', 'printCupon']),
41
+        ];
42
+    }
43
+
44
+    public function index(CuponDataTable $dataTable)
45
+    {
46
+        $dataTable->attivita_id = Session::get('attivita_attuale');
47
+        return $dataTable->render('cupon.index');
48
+    }
49
+
50
+    public function stampaCupon(Request $request)
51
+    {
52
+        $attivitaId = Session::get('attivita_attuale');
53
+        $cupons = Cupon::where('attivita_id', $attivitaId)->orderBy('id', 'desc')->get();
54
+        $stampanti = Dispositivo::where('attivita_id', $attivitaId)
55
+            ->where('tipo', Dispositivo::STAMPANTE)
56
+            ->where('is_attivo', true)
57
+            ->orderBy('nome')
58
+            ->get();
59
+
60
+        return view('cupon.stampa-cupon', compact('cupons', 'stampanti'));
61
+    }
62
+
63
+
64
+    public function pdfCupon(Request $request)
65
+    {
66
+        $cupons = $this->cuponsSelezionati($request);
67
+
68
+        return Pdf::loadView('cupon.pdf', [
69
+            'cupons' => $cupons,
70
+            'nomeAttivita' => Attivita::find(Session::get('attivita_attuale'))?->nome ?? '',
71
+        ])->setPaper('a4', 'portrait')->download('cupon.pdf');
72
+    }
73
+
74
+    public function pdfCuponPersonalizzato(Request $request)
75
+    {
76
+        $attivitaId = Session::get('attivita_attuale');
77
+        $cupons = $this->cuponsSelezionati($request);
78
+
79
+        return Pdf::loadView('cupon.pdf-personalizzato', [
80
+            'cupons' => $cupons,
81
+            'templatePath' => Storage::disk('templateCupon')->path($attivitaId.'/template.png'),
82
+            'layout' => [
83
+              'show_importo' => false,
84
+              'show_nominativo' => false,
85
+              'show_validita' => false,
86
+              'codice' => [
87
+                'top' => '18mm',
88
+                'left' => '12mm',
89
+                'font_size' => '18pt',
90
+              ],
91
+            ],
92
+          ])->setPaper('a4', 'portrait')->download('cupon.pdf-personalizzato');
93
+    }
94
+
95
+    public function uploadCuponTemplate(Request $request)
96
+    {
97
+        $request->validate([
98
+            'template' => 'required|image|mimes:png,jpg,jpeg,webp|max:5120',
99
+        ]);
100
+        $attivitaId = Session::get('attivita_attuale');
101
+        AttivitaService::garantisciAttivita($attivitaId);
102
+        $path = $attivitaId.'/template.png';
103
+        // sovrascrive sempre lo stesso file
104
+        Storage::disk('templateCupon')->put(
105
+            $path,
106
+            file_get_contents($request->file('template')->getRealPath())
107
+        );
108
+        return response()->json([
109
+            'success' => true,
110
+            'message' => 'Grafica salvata.',
111
+            'url' => Storage::disk('templateCupon')->url($path),
112
+        ]);
113
+    }
114
+    
115
+
116
+    public function store(CuponDataTableEditor $editor)
117
+    {
118
+        $request = request();
119
+        $input = $request->all();
120
+        if($request->has('action')){
121
+          switch($input['action']){
122
+            case 'create':
123
+              if(!Auth::user()->can('create-cupon')) return;
124
+              break;
125
+            case 'edit':
126
+              if(!Auth::user()->can('edit-cupon')) return;
127
+              break;
128
+            case 'remove':
129
+              if(!Auth::user()->can('delete-cupon')) return;
130
+              break;
131
+          }
132
+        }
133
+        return $editor->process($request);
134
+    }
135
+
136
+    public function generaBatch(Request $request)
137
+    {
138
+        AttivitaService::garantisciAttivita(Session::get('attivita_attuale'));
139
+        
140
+        switch($request->modo){
141
+            case 'file':
142
+                //colonne CSV: nominativo,importo,validita_da,validita_a,email
143
+
144
+                $file = $request->file('file')->getRealPath();
145
+                $fileOpen = fopen($file, 'r');
146
+                fgetcsv($fileOpen, 0, ','); // scarta nominativo,importo,validita_da,validita_a
147
+                while (($line = fgetcsv($fileOpen, 0, ',')) !== false) {
148
+                    $this->generaCupon([
149
+                        'importo' => doubleval($line[1])?? $request->importo,
150
+                        'validita_da' => Carbon::parse($line[2])?? $request->validita_da,
151
+                        'validita_a' => Carbon::parse($line[3])?? $request->validita_a,
152
+                        'nominativo' => $line[0]?? '',
153
+                        'email' => $line[4]?? '',
154
+                    ]);
155
+                                };
156
+                break;
157
+            case 'numerati':
158
+                
159
+                for($i = $request->da; $i <= $request->a; $i++){
160
+                    $this->generaCupon([
161
+                        'importo' => $request->importo,
162
+                        'validita_da' => Carbon::parse($request->validita_da),
163
+                        'validita_a' => Carbon::parse($request->validita_a),
164
+                        'nominativo' => $request->nominativo?? '',
165
+                        'email' => $request->email?? '',
166
+                    ]);
167
+                }
168
+                break;
169
+        }
170
+
171
+        return redirect()->route('cupon.index')->with('success', 'Cupon generati con successo');
172
+    }
173
+
174
+    public function check(Request $request)
175
+    {
176
+        $cupon = Cupon::where('codice', $request->cupon_codice)->where('attivita_id', session('attivita_attuale'))->first();
177
+        if($cupon){
178
+            // Marca come scaduto se la data di fine validità è passata
179
+            if($cupon->stato == Cupon::GENERATO && $cupon->validita_a < Carbon::today()){
180
+                $cupon->stato = Cupon::SCADUTO;
181
+                $cupon->save();
182
+            }
183
+
184
+            // Cupon non ancora valido (troppo presto)
185
+            if($cupon->stato == Cupon::GENERATO && $cupon->validita_da->startOfDay() > Carbon::today()){
186
+                return response()->json(['success' => false, 'message' => 'Cupon non ancora valido', 'validita_da' => $cupon->validita_da->format('d/m/Y')]);
187
+            }
188
+
189
+            $ordine = Ordine::find($request->ordine_id);
190
+            if (! $ordine || (int) $ordine->attivita_id !== (int) session('attivita_attuale')) {
191
+                return response()->json(['success' => false, 'message' => 'Ordine non trovato']);
192
+            }
193
+
194
+
195
+        switch($cupon->stato){
196
+            case Cupon::GENERATO:
197
+                $importoValido = null;
198
+                $message = null;
199
+
200
+                if(!$this->checkImporto($cupon, $ordine->prezzo)){
201
+                    $success = false;
202
+                    $importoValido = false;
203
+                    $message = 'Importo del cupon non sufficiente.';
204
+                }else{
205
+                    $success = true;
206
+                    $importoValido = true;
207
+                    $message = 'Cupon utilizzabile';
208
+                }
209
+
210
+                return response()->json([
211
+                    'success'    => $success,
212
+                    'message'    => $message,
213
+                    'importo'    => $cupon->importo,
214
+                    'nominativo' => $cupon->nominativo,
215
+                    'validita_da' => $cupon->validita_da?->format('d/m/Y'),
216
+                    'validita_a'  => $cupon->validita_a?->format('d/m/Y'),
217
+                    'oggi' => $oggi = $cupon->validita_da->isSameDay($cupon->validita_a) && $cupon->validita_da->isSameDay(Carbon::today()),
218
+                ]);
219
+            case Cupon::USATO:
220
+                return response()->json(['success' => false, 'message' => 'Cupon già utilizzato']);
221
+            case Cupon::SCADUTO:
222
+                return response()->json(['success' => false, 'message' => 'Cupon scaduto', 'validita_a' => $cupon->validita_a?->format('d/m/Y')]);
223
+            default:
224
+                return response()->json(['success' => false, 'message' => 'Cupon non trovato']);
225
+        }
226
+        }else{
227
+            return response()->json(['success' => false, 'message' => 'Cupon non trovato']);
228
+        }
229
+    }
230
+
231
+    public function printCupon(Request $request)
232
+    {
233
+        $request->validate([
234
+            'ids' => 'required|array|min:1',
235
+            'ids.*' => 'integer',
236
+            'stampante_id' => 'required|integer|exists:dispositivo,id',
237
+        ]);
238
+
239
+        $attivitaId = Session::get('attivita_attuale');
240
+        $ids = $request->input('ids', []);
241
+
242
+        $stampante = Dispositivo::where('id', $request->stampante_id)
243
+            ->where('attivita_id', $attivitaId)
244
+            ->where('tipo', Dispositivo::STAMPANTE)
245
+            ->first();
246
+
247
+        if (! $stampante) {
248
+            return response()->json([
249
+                'success' => false,
250
+                'message' => 'Stampante non valida per questa attività.',
251
+            ], 422);
252
+        }
253
+
254
+        $cupons = Cupon::where('attivita_id', $attivitaId)
255
+            ->whereIn('id', $ids)
256
+            ->get();
257
+
258
+        if ($cupons->count() !== count($ids)) {
259
+            return response()->json([
260
+                'success' => false,
261
+                'message' => 'Alcuni cupon selezionati non esistono o non appartengono all\'attività corrente.',
262
+            ], 422);
263
+        }
264
+
265
+        foreach ($cupons as $cupon) {
266
+            $printJob = new PrintJob();
267
+            $printJob->fill([
268
+                'printable_id' => $cupon->id,
269
+                'tipo' => PrintJob::TIPO_CUPON,
270
+                'stampante_id' => $stampante->id,
271
+                'stato' => PrintJob::STATO_IN_ATTESA,
272
+                'payload' => null,
273
+            ]);
274
+            $printJob->save();
275
+            ElaboraJobStampa::dispatch($printJob->id);
276
+        }
277
+
278
+        return response()->json([
279
+            'success' => true,
280
+            'message' => 'Stampa inviata: '.$cupons->count().' cupon in coda.',
281
+            'count' => $cupons->count(),
282
+        ]);
283
+    }
284
+
285
+    public function checklistCupon(Request $request)
286
+    {
287
+        $attivitaId = Session::get('attivita_attuale');
288
+        $cupons = $this->cuponsSelezionati($request);
289
+
290
+        $stati = Cupon::getStati();
291
+        $statoKey = $request->input('stato');
292
+        $statoLabel = $statoKey
293
+            ? ($stati[$statoKey]['label'] ?? $statoKey)
294
+            : 'Tutti';
295
+
296
+        $filtri = [
297
+            'Codice' => $request->filled('codice') ? strtoupper($request->input('codice')) : '—',
298
+            'Solo validi oggi' => $request->boolean('oggi') ? 'Sì' : 'No',
299
+            'Validità da' => $request->filled('validita_da')
300
+                ? Carbon::parse($request->input('validita_da'))->format('d/m/Y')
301
+                : '—',
302
+            'Validità a' => $request->filled('validita_a')
303
+                ? Carbon::parse($request->input('validita_a'))->format('d/m/Y')
304
+                : '—',
305
+            'Stato' => $statoLabel,
306
+            'Tag' => $request->filled('tag') ? $request->input('tag') : '—',
307
+            'Limite' => $request->filled('limite') ? $request->input('limite') : '—',
308
+        ];
309
+
310
+        return Pdf::loadView('cupon.checklist', [
311
+            'cupons' => $cupons,
312
+            'nomeAttivita' => Attivita::find($attivitaId)?->nome ?? '',
313
+            'filtri' => $filtri,
314
+            'generatoIl' => Carbon::now()->format('d/m/Y H:i'),
315
+            'totale' => $cupons->count(),
316
+            'stati' => $stati,
317
+        ])->setPaper('a4', 'portrait')->download('checklist-cupon.pdf');
318
+    }
319
+
320
+    /**
321
+     * Cupon selezionati da ids[] (stampa PDF / checklist), scoped all'attività corrente.
322
+     */
323
+    private function cuponsSelezionati(Request $request)
324
+    {
325
+        $ids = array_values(array_filter((array) $request->input('ids', [])));
326
+        if (empty($ids)) {
327
+            abort(422, 'Nessun cupon selezionato.');
328
+        }
329
+
330
+        $cupons = Cupon::where('attivita_id', Session::get('attivita_attuale'))
331
+            ->whereIn('id', $ids)
332
+            ->orderBy('codice')
333
+            ->get();
334
+
335
+        if ($cupons->isEmpty()) {
336
+            abort(404, 'Nessun cupon trovato.');
337
+        }
338
+
339
+        return $cupons;
340
+    }
341
+
342
+//PRIVATE
343
+    private function generaCupon($data)
344
+    {
345
+        $codice = $this->generaCodiceCupon();
346
+        while (Cupon::where('codice', $codice)->exists()) {
347
+            $codice = $this->generaCodiceCupon();
348
+        }
349
+
350
+        Cupon::create([
351
+            'attivita_id' => Session::get('attivita_attuale'),
352
+            'codice' => $codice,
353
+            'importo' => $data['importo'],
354
+            'validita_da' => $data['validita_da'],
355
+            'validita_a' => $data['validita_a'],
356
+            'stato' => Cupon::GENERATO,
357
+            'nominativo' => $data['nominativo']?? '',
358
+            'email' => $data['email']?? '',
359
+        ]);
360
+    }
361
+
362
+    /**
363
+     * Codice a prova di dettatura (5 caratteri): mix lettere + numeri.
364
+     * Esclusi: 0/O, 1/I/L, 5/S, 8/B, 2/Z.
365
+     */
366
+    public function generaCodiceCupon(int $length = 5): string
367
+    {
368
+        $lettere = 'ACDEFGHJKMNPQRTUVWXY';
369
+        $numeri = '34679';
370
+        $chars = $lettere.$numeri;
371
+
372
+        // Almeno 2 numeri e il resto lettere, poi shuffle (sempre 5 caratteri)
373
+        $numCount = min(2, $length - 1);
374
+        $letterCount = $length - $numCount;
375
+
376
+        $codice = '';
377
+        for ($i = 0; $i < $letterCount; $i++) {
378
+            $codice .= $lettere[random_int(0, strlen($lettere) - 1)];
379
+        }
380
+        for ($i = 0; $i < $numCount; $i++) {
381
+            $codice .= $numeri[random_int(0, strlen($numeri) - 1)];
382
+        }
383
+
384
+        return str_shuffle($codice);
385
+    }
386
+
387
+    private function checkImporto(Cupon $cupon, $importo){
388
+        if($cupon->importo >= $importo  ){
389
+            return true;
390
+        }
391
+        return false;
392
+    }
393
+
394
+
395
+}

+ 4
- 0
app/Http/Controllers/DispositivoController.php Просмотреть файл

@@ -2,11 +2,14 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Dispositivo;
7 9
 use App\DataTables\DispositivoDataTable;
8 10
 use App\DataTables\DispositivoDataTableEditor;
9 11
 use Illuminate\Support\Facades\Auth;
12
+use Illuminate\Support\Facades\Session;
10 13
 
11 14
 
12 15
 class DispositivoController extends Controller
@@ -29,6 +32,7 @@ class DispositivoController extends Controller
29 32
     
30 33
     public function index(DispositivoDataTable $dataTable)
31 34
     {
35
+        $dataTable->attivita_id = Session::get('attivita_attuale');
32 36
         return $dataTable->render('dispositivo.index');
33 37
     }
34 38
     public function store(DispositivoDataTableEditor $editor)

+ 86
- 30
app/Http/Controllers/EndpointController.php Просмотреть файл

@@ -2,20 +2,23 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use App\Models\Endpoint;
7
+use App\Models\PrintJob;
8
+use App\Models\Attivita;
9
+use App\Models\Dispositivo;
5 10
 use Illuminate\Http\Request;
6 11
 use Illuminate\Support\Facades\Log;
7 12
 use Illuminate\Support\Facades\Http;
8
-use App\Models\Endpoint;
9
-use App\Models\Dispositivo;
10
-use App\Models\PrintJob;
11
-use App\DataTables\EndpointDataTable;
13
+use Illuminate\Routing\Controllers\Middleware;
12 14
 use App\DataTables\EndpointDataTableEditor;
15
+use App\DataTables\EndpointDataTable;
13 16
 use Illuminate\Support\Facades\Validator;
14
-use App\Models\Attivita;
15
-use Illuminate\Support\Str;
16 17
 use Illuminate\Support\Facades\Session;
17
-use Illuminate\Support\Facades\Auth;
18 18
 use Illuminate\Support\Facades\Storage;
19
+use Illuminate\Support\Facades\Auth;
20
+use Illuminate\Support\Str;
21
+use App\Services\Attivita\AttivitaService;
19 22
 
20 23
 class EndpointController extends Controller
21 24
 {
@@ -31,9 +34,9 @@ class EndpointController extends Controller
31 34
     public static function middleware(): array
32 35
     {
33 36
         return [
34
-            new Middleware('permission:view-endpoint', only: ['index', 'show', 'istruzioni']),
37
+            new Middleware('permission:view-endpoint', only: ['index', 'show', 'istruzioni', 'download_festagent']),
35 38
             new Middleware('permission:create-endpoint|edit-endpoint|delete-endpoint', only: ['store', 'update', 'destroy']),
36
-            new Middleware('permission:create-endpoint', only: ['richiedi_nuovo_product_key']),
39
+            new Middleware('permission:create-endpoint', only: ['richiedi_nuovo_product_key', 'collega_questo_pc']),
37 40
         ];
38 41
     }
39 42
 
@@ -52,6 +55,8 @@ class EndpointController extends Controller
52 55
             abort(404);
53 56
         }
54 57
 
58
+        AttivitaService::garantisciAttivita($endpoint->attivita_id);
59
+        
55 60
         return view('endpoint.show', compact('endpoint'));
56 61
     }
57 62
 
@@ -67,7 +72,10 @@ class EndpointController extends Controller
67 72
     //deeplink
68 73
     public function collega_questo_pc(Request $request)
69 74
     {
70
-        $endpoint = Endpoint::where('attivita_id', Session::get('attivita_attuale'))
75
+        $attivitaId = Session::get('attivita_attuale');
76
+        AttivitaService::garantisciAttivita($attivitaId);
77
+
78
+        $endpoint = Endpoint::where('attivita_id', $attivitaId)
71 79
         ->where('user_id', $request->user()->id)
72 80
         ->where('status', Endpoint::NON_REGISTRATO)
73 81
         ->first();
@@ -78,7 +86,7 @@ class EndpointController extends Controller
78 86
         }else{
79 87
 
80 88
         $endpoint = new Endpoint();
81
-        $endpoint->attivita_id = $request->attivita_id;
89
+        $endpoint->attivita_id = $attivitaId;
82 90
         $endpoint->user_id = $request->user()->id;
83 91
         $endpoint->deeplink_token = ['token' => Str::random(32) , 'timestamp' => now()->timestamp , 'status' => 'pending'];
84 92
         $endpoint->product_key = $this->creaProductKey();
@@ -95,7 +103,7 @@ class EndpointController extends Controller
95 103
             'message' => 'Endpoint collegato con successo',
96 104
             'status' => 'success',
97 105
             'success' => true,
98
-            'endpoint' => $endpoint,
106
+            'endpoint' => $endpoint->makeHidden(['product_key', 'secret', 'deeplink_token', 'token']),
99 107
             'url' => url('fest-agent://pair?token=' . $endpoint->deeplink_token['token'] . '&server=' . $server),
100 108
         ]);
101 109
     }
@@ -132,6 +140,7 @@ class EndpointController extends Controller
132 140
         }
133 141
         $endpoint->update([
134 142
             'status' => Endpoint::DISABILITATO,
143
+            'token' => null,
135 144
         ]);
136 145
         return response()->json([
137 146
             'message' => 'Endpoint disattivato con successo',
@@ -145,13 +154,29 @@ class EndpointController extends Controller
145 154
             'token' => 'required|string|max:255',
146 155
         ]);
147 156
         $endpoint = Endpoint::where('deeplink_token->token', $request->token)->first();
157
+
158
+        //Se non c'è return
148 159
         if(!$endpoint){
149 160
             return response()->json(['message' => 'Endpoint non trovato', 'status' => 'error', 'success' => false], 404);
150 161
         }
162
+
163
+        // Se scaduto dopo 10 minuti return
164
+        if($endpoint->deeplink_token['timestamp'] < now()->subMinutes(10)->timestamp){
165
+            $endpoint->deeplink_token['status'] = 'expired';
166
+            $endpoint->save();
167
+            return response()->json(['message' => 'Token scaduto', 'status' => 'error', 'success' => false], 400);
168
+        }
169
+
170
+        //Se già usato return
171
+        if($endpoint->deeplink_token['status'] == 'paired'){
172
+            return response()->json(['message' => 'Endpoint già registrato', 'status' => 'error', 'success' => false], 400);
173
+        }
174
+
175
+
151 176
         $deeplink_token = $endpoint->deeplink_token;
152 177
         $deeplink_token['status'] = 'paired';
153 178
         $endpoint->update([
154
-            'deeplink_token' => $deeplink_token,
179
+            'deeplink_token' => '',//$deeplink_token,
155 180
             'status' => Endpoint::REGISTRATO,
156 181
             'token' => Str::random(32),
157 182
         ]);
@@ -159,7 +184,7 @@ class EndpointController extends Controller
159 184
             'message' => 'Endpoint registrato con successo',
160 185
             'status' => 'success',
161 186
             'success' => true,
162
-            'endpoint' => $endpoint,
187
+            'endpoint' => $endpoint->makeHidden(['product_key', 'secret', 'deeplink_token']),
163 188
             'token' => $endpoint->token,
164 189
         ]);
165 190
     }
@@ -192,8 +217,8 @@ class EndpointController extends Controller
192 217
 
193 218
     public function stampanti_register(Request $request)
194 219
     {
195
-        Log::info('stampanti_register');
196
-        Log::info($request->all());
220
+        // Log::info('stampanti_register');
221
+        // Log::info($request->all());
197 222
 
198 223
         $stampanti_da_registrare = $request->input('stampanti', []);
199 224
         $endpoint = $request->endpoint;
@@ -287,12 +312,16 @@ class EndpointController extends Controller
287 312
     public function esito_stampa(Request $request)
288 313
 {
289 314
     $request->validate([
290
-        'printJob_id' => 'required|integer|exists:print_job,id',
315
+        'printJob_id' => 'required|integer',
291 316
         'esito' => 'required|string|in:success,error',
292 317
     ]);
293 318
 
294 319
     $printJob = PrintJob::query()
295 320
         ->whereKey($request->printJob_id)
321
+        ->whereIn(
322
+            'stampante_id',
323
+            $request->endpoint->stampanti()->pluck('id')
324
+        )
296 325
         ->first();
297 326
 
298 327
     if (! $printJob) {
@@ -365,11 +394,28 @@ class EndpointController extends Controller
365 394
                     break;
366 395
             }
367 396
         }
397
+        if (in_array($request->input('action'), ['edit', 'remove'], true)) {
398
+            foreach (array_keys($request->input('data', [])) as $id) {
399
+                AttivitaService::garantisciAttivita(Endpoint::find($id)?->attivita_id);
400
+            }
401
+        }
402
+
368 403
         return $editor->process($request);
369 404
     }
370 405
     public function index_api(Request $request)
371 406
     {
372
-        $endpoints = Endpoint::all();
407
+        if($request->attivita_id){
408
+            $attivita_id = $request->attivita_id;
409
+        }else{
410
+            return response()->json([
411
+                'message' => 'Attività non trovata',
412
+                'status' => 'error',
413
+                'success' => false,
414
+            ], 404);
415
+        }
416
+        AttivitaService::api_garantisciAttivita($attivita_id);
417
+
418
+        $endpoints = Endpoint::where('attivita_id', $attivita_id)->get()->makeHidden(['product_key', 'secret', 'deeplink_token','token']);
373 419
         return response()->json([
374 420
          'message' => 'Endpoint trovati con successo',
375 421
          'count' => $endpoints->count(),
@@ -384,11 +430,11 @@ class EndpointController extends Controller
384 430
 
385 431
         if($request->has('first_time') && $request->first_time == true){
386 432
             //la prima registrazione
387
-            Log::info('api_register_product_key');
388
-            Log::info('FIRST TIME');
389
-            Log::info('Request: ' . json_encode($request->all()));
433
+            // Log::info('api_register_product_key');
434
+            // Log::info('FIRST TIME');
435
+            // Log::info('Request: ' . json_encode($request->all()));
390 436
         $validator = Validator::make($request->all(), [
391
-            'product_key' => 'required|string|max:25,exists:endpoint,product_key',
437
+            'product_key' => 'required|string|max:25|exists:endpoint,product_key',
392 438
         ], [
393 439
             'product_key.required' => 'Il product key è richiesto',
394 440
             'product_key.string' => 'Il product key deve essere una stringa',
@@ -398,7 +444,7 @@ class EndpointController extends Controller
398 444
 
399 445
         if($validator->fails()){
400 446
             Log::error('api_register_product_key');
401
-            Log::error('Request: ' . $request->all());
447
+            // Log::error('Request: ' . $request->all());
402 448
             Log::error('Validator fails: ' . $validator->messages());
403 449
             return response()->json([
404 450
                 'message' => $validator->messages(),
@@ -416,10 +462,9 @@ class EndpointController extends Controller
416 462
                 'status' => 'error',
417 463
                 'success' => false,
418 464
             ], 404);
419
-        }elseif($endpoint->status == Endpoint::REGISTRATO){
420
-            Log::error('Endpoint già registrato');
465
+        }elseif($endpoint->status != Endpoint::NON_REGISTRATO){
421 466
             return response()->json([
422
-                'message' => 'Endpoint già registrato',
467
+                'message' => 'Endpoint non può essere registrato',
423 468
                 'status' => 'error',
424 469
                 'success' => false,
425 470
             ], 400);
@@ -451,7 +496,7 @@ class EndpointController extends Controller
451 496
             'message' => 'Endpoint trovato con successo',
452 497
             'status' => 'success',
453 498
             'success' => true,
454
-            'endpoint' => $endpoint,
499
+            'endpoint' => $endpoint->makeHidden(['product_key', 'secret', 'deeplink_token','token']),
455 500
             'licenza' => $licenza??null,
456 501
             'attivita' => $attivita??null,
457 502
         ]);
@@ -460,13 +505,14 @@ class EndpointController extends Controller
460 505
         //se non è la prima registrazione può modificare gli attributi dell'endpoint
461 506
         Log::info('api_register_product_key');
462 507
         Log::info('NOT ft');
463
-        Log::info('Request: ' . json_encode($request->all()));
508
+        // Log::info('Request: ' . json_encode($request->all()));
464 509
         // dd($request->all() , 'NOT ft');
465 510
 
466 511
         $validator = Validator::make($request->all(), [
467 512
             'label' => 'required|string|max:255',
468 513
             'descrizione' => 'nullable|string|max:255',
469 514
             'ubicazione' => 'nullable|string|max:255',
515
+            'product_key' => 'nullable|string|max:25|exists:endpoint,product_key',
470 516
         ], [
471 517
             'label.required' => 'Il label è richiesto',
472 518
             'label.string' => 'Il label deve essere una stringa',
@@ -475,6 +521,9 @@ class EndpointController extends Controller
475 521
             'descrizione.max' => 'La descrizione deve essere lungo al massimo 255 caratteri',
476 522
             'ubicazione.string' => 'L\'ubicazione deve essere una stringa',
477 523
             'ubicazione.max' => 'L\'ubicazione deve essere lungo al massimo 255 caratteri',
524
+            'product_key.string' => 'Il product key deve essere una stringa',
525
+            'product_key.max' => 'Il product key deve essere lungo al massimo 25 caratteri',
526
+            'product_key.exists' => 'Il product key non è valido',
478 527
         ]);
479 528
 
480 529
         if($validator->fails()){
@@ -490,7 +539,7 @@ class EndpointController extends Controller
490 539
         $endpoint = Endpoint::where('product_key', $request->product_key)->where('status', Endpoint::REGISTRATO)->first();
491 540
         if(!$endpoint){
492 541
             Log::error('Endpoint non trovato');
493
-            Log::error('Request: ' . json_encode($request->all()));
542
+            // Log::error('Request: ' . json_encode($request->all()));
494 543
             return response()->json([
495 544
                 'message' => 'Endpoint non trovato',
496 545
                 'status' => 'error',
@@ -510,7 +559,7 @@ class EndpointController extends Controller
510 559
             'message' => 'Endpoint aggiornato con successo',
511 560
             'status' => 'success',
512 561
             'success' => true,
513
-            'endpoint' => $endpoint,
562
+            'endpoint' => $endpoint->makeHidden(['product_key', 'secret', 'deeplink_token','token']),
514 563
             'token' => $endpoint->token,
515 564
         ]);
516 565
 
@@ -527,6 +576,7 @@ class EndpointController extends Controller
527 576
             'attivita_id.exists' => 'L\'attività non è valida',
528 577
         ]);
529 578
 
579
+        AttivitaService::garantisciAttivita($request->attivita_id);
530 580
 
531 581
         $attivita = Attivita::find($request->attivita_id);
532 582
         
@@ -551,6 +601,12 @@ class EndpointController extends Controller
551 601
 
552 602
     public function download_festagent(Request $request)
553 603
     {
604
+        $filePath = '001_fest.exe';
605
+
606
+        if (!Storage::disk('festAgent')->exists($filePath)) {
607
+            abort(404, 'Il file richiesto non esiste.');
608
+        }
609
+   
554 610
         return Storage::disk('festAgent')->download('001_fest.exe', '001_fest.exe');   
555 611
     }
556 612
 }

+ 696
- 13
app/Http/Controllers/EventoController.php Просмотреть файл

@@ -4,10 +4,19 @@ namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6 6
 use App\Models\Evento;
7
+use App\Models\EventoForm;
8
+use App\Models\OpzioneForm;
9
+use App\Models\Prenotazione;
7 10
 use App\DataTables\EventoDataTable;
8 11
 use App\DataTables\EventoDataTableEditor;
9 12
 use Illuminate\Support\Facades\Auth;
10
-use App\DataTables\EventoFormDataTable;
13
+use Illuminate\Support\Facades\DB;
14
+use Illuminate\Support\Facades\Http;
15
+use Illuminate\Support\Facades\Storage;
16
+use Illuminate\Routing\Controllers\Middleware;
17
+use Illuminate\Support\Facades\Session;
18
+use Illuminate\Support\Str;
19
+use App\Services\Attivita\AttivitaService;
11 20
 
12 21
 
13 22
 class EventoController extends Controller
@@ -20,18 +29,31 @@ class EventoController extends Controller
20 29
         'delete-evento' => 'Elimina',
21 30
     ];
22 31
 
32
+    // ADMIN
23 33
     public static function middleware(): array
24 34
     {
25 35
         return [
26
-            new Middleware('permission:view-evento', only: ['index']),
27
-            new Middleware('permission:create-evento|edit-evento|delete-evento', only: ['store', 'update', 'destroy']),
36
+            new Middleware('permission:view-evento', only: ['index', 'admin_show']),
37
+            new Middleware('permission:create-evento|edit-evento|delete-evento', only: [
38
+                'store', 'update', 'destroy', 'crea', 'edit', 'geocodeLuogo',
39
+                'gallery_edit', 'gallery_upload',
40
+                'applicaPresetDomande',
41
+                'storeDomanda', 'updateDomanda', 'destroyDomanda', 'reorderDomande',
42
+                'uploadLocandina', 'destroyLocandina', 'uploadCopertina', 'destroyCopertina',
43
+            ]),
28 44
         ];
29 45
     }
30 46
 
47
+    // ADMIN
31 48
     public function index(EventoDatatable $dataTable)
32 49
     {
33
-        return $dataTable->render('evento.index');
50
+      $dataTable->attivita_id = Session::get('attivita_attuale');
51
+      return $dataTable->render('evento.index', [
52
+        'attivita_id' => Session::get('attivita_attuale'),
53
+      ]);
34 54
     }
55
+
56
+    // ADMIN
35 57
     public function store(EventoDataTableEditor $editor)
36 58
     {
37 59
         $request = request();
@@ -52,18 +74,106 @@ class EventoController extends Controller
52 74
         return $editor->process($request);
53 75
     }
54 76
 
55
-    public function show(Request $request)
77
+    // ADMIN — cruscotto evento
78
+    public function admin_show(Request $request)
56 79
     {
57
-      // dd($request->all());
58
-        $evento = Evento::find($request->get('evento_id'));
80
+        $evento = Evento::with([
81
+            'attivita',
82
+            'sale.tavoli' => fn ($q) => $q->where('is_attivo', true),
83
+        ])->find($request->get('evento_id'));
84
+
85
+        if (! $evento) {
86
+            return redirect()->route('evento.index')->with('error', 'Evento non trovato');
87
+        }
88
+        
89
+        AttivitaService::garantisciEventoDiQuestaAttivita($evento);
90
+
91
+        $prenotazioni = $evento->prenotazioni()
92
+            ->whereNotIn('stato', [
93
+                Prenotazione::STATO_CANCELLATA,
94
+                Prenotazione::STATO_ANNULLATA,
95
+                Prenotazione::STATO_RIFIUTATA,
96
+            ]);
97
+
98
+        $galleria = is_array(json_decode($evento->galleria, true))
99
+            ? json_decode($evento->galleria, true)
100
+            : [];
101
+
102
+        $disk = Storage::disk('eventi');
103
+        $locandinaUrl = null;
104
+        if (filled($evento->immagine) && $disk->exists($evento->immagine)) {
105
+            $locandinaUrl = $disk->url($evento->immagine).'?v='.$disk->lastModified($evento->immagine);
106
+        }
107
+
108
+        $postiEvento = $evento->posti !== null ? (int) $evento->posti : null;
109
+        $postiPiantina = (int) $evento->sale->sum(fn ($sala) => $sala->tavoli->sum('posti'));
110
+        $tavoliCount = (int) $evento->sale->sum(fn ($sala) => $sala->tavoli->count());
111
+        $alertPosti = null;
112
+        if ($postiEvento !== null && $postiPiantina !== $postiEvento) {
113
+            $alertPosti = [
114
+                'tipo' => $postiPiantina < $postiEvento ? 'warning' : 'info',
115
+                'posti_evento' => $postiEvento,
116
+                'posti_piantina' => $postiPiantina,
117
+            ];
118
+        }
119
+
120
+        $stats = [
121
+            'prenotazioni' => (clone $prenotazioni)->count(),
122
+            'confermate' => (clone $prenotazioni)->where('confermata', true)->count(),
123
+            'coperti_confermati' => (int) $evento->getCopertiConfermati(),
124
+            'posti' => $postiEvento,
125
+            'posti_piantina' => $postiPiantina,
126
+            'tavoli' => $tavoliCount,
127
+            'galleria' => count($galleria),
128
+            'prenotabile' => $evento->isPrenotabileOra(),
129
+            'messaggio_prenotazione' => $evento->messaggioStatoPrenotazione(),
130
+        ];
131
+
132
+        return view('evento.admin_show', [
133
+            'evento' => $evento,
134
+            'stats' => $stats,
135
+            'alertPosti' => $alertPosti,
136
+            'locandinaUrl' => $locandinaUrl,
137
+            'stati' => Evento::stati(),
138
+        ]);
139
+    }
140
+
141
+    // CLIENTE — scheda pubblica evento
142
+    public function show(string $codice)
143
+    {
144
+        $evento = Evento::with('attivita')->where('codice', $codice)->first();
145
+
146
+        if (! $evento || ! $evento->isVisibilePublicamente()) {
147
+            return redirect()->route('welcome')->with('error', 'Evento non trovato o non disponibile.');
148
+        }
149
+
150
+        $galleriaItems = is_array(json_decode($evento->galleria, true)) ? json_decode($evento->galleria, true) : [];
151
+
59 152
         return view('evento.show', [
60
-          'evento' => $evento , 
61
-          'galleriaItems' => is_array(json_decode($evento->galleria, true)) ? json_decode($evento->galleria, true) : []]);
153
+            'evento' => $evento,
154
+            'galleriaItems' => $galleriaItems,
155
+            'prenotabileOra' => $evento->isPrenotabileOra(),
156
+            'messaggioPrenotazione' => $evento->messaggioStatoPrenotazione(),
157
+        ]);
158
+    }
159
+
160
+    // CLIENTE — redirect da ?evento_id=… alla scheda pubblica con codice
161
+    public function showLegacy(Request $request)
162
+    {
163
+        $evento = Evento::find($request->get('evento_id'));
164
+        if (! $evento) {
165
+            return redirect()->route('welcome')->with('error', 'Evento non trovato o non disponibile.');
166
+        }
167
+
168
+        return redirect()->route('evento.show', ['codice' => $evento->publicCodice()]);
62 169
     }
63 170
 
171
+    // ADMIN
64 172
     public function gallery_edit(Request $request)
65 173
     {
66 174
       $evento = Evento::find($request->get('evento_id'));
175
+      if(!$evento) return redirect()->route('evento.index')->with('error', 'Evento non trovato');
176
+      AttivitaService::garantisciEventoDiQuestaAttivita($evento);
67 177
 
68 178
       return view('evento.gallery.edit', [
69 179
           'evento' => $evento,
@@ -71,9 +181,13 @@ class EventoController extends Controller
71 181
       ]);
72 182
     }
73 183
 
184
+    // ADMIN
74 185
     public function gallery_upload(Request $request)
75 186
     {
76 187
       $evento = Evento::find($request->get('evento_id'));
188
+      if(!$evento) return redirect()->route('evento.index')->with('error', 'Evento non trovato');
189
+      AttivitaService::garantisciEventoDiQuestaAttivita($evento);
190
+
77 191
       $galleria = json_decode($evento->galleria);
78 192
       if($galleria == null) $galleria = [];
79 193
       $nome = $request->file('file')->getClientOriginalName();
@@ -86,11 +200,580 @@ class EventoController extends Controller
86 200
       return redirect()->route('evento.gallery.edit', ['evento_id' => $evento->id])->with('success', 'Foto aggiunta con successo');
87 201
     }
88 202
 
89
-    public function edit(Request $request , EventoFormDataTable $dataTable)
203
+    // ADMIN
204
+    public function edit(Request $request)
90 205
     {
91
-      $evento = Evento::find($request->get('evento_id'));
92
-      $dataTable->evento_id = $evento->id;
93
-      return $dataTable->render('evento.edit', compact('evento'));
206
+      $evento = Evento::with(['attivita', 'form' => function ($q) {
207
+        $q->orderBy('ordine_visualizzazione')->orderBy('id')->with(['opzioni_form' => function ($oq) {
208
+          $oq->orderBy('ordine')->orderBy('id');
209
+        }]);
210
+      }])->find($request->get('evento_id'));
211
+
212
+      if (! $evento) {
213
+        return redirect()->route('evento.index')->with('error', 'Evento non trovato');
214
+      }
215
+
216
+      AttivitaService::garantisciEventoDiQuestaAttivita($evento);
217
+
218
+      // Se non ci sono domande, applica subito il set "pasto" così sono visibili
219
+      if ($evento->form->isEmpty()) {
220
+        $this->applyDomandePreset($evento, 'pasto');
221
+        $evento->load(['form' => function ($q) {
222
+          $q->orderBy('ordine_visualizzazione')->orderBy('id')->with(['opzioni_form' => function ($oq) {
223
+            $oq->orderBy('ordine')->orderBy('id');
224
+          }]);
225
+        }]);
226
+      }
227
+
228
+      return view('evento.edit', compact('evento'));
94 229
     }
95 230
 
231
+    // ADMIN
232
+    public function crea(Request $request)
233
+    {
234
+      $attivitaId = Session::get('attivita_attuale');
235
+      if (! (int) $attivitaId) {
236
+        abort(404);
237
+      }
238
+      AttivitaService::garantisciAttivita($attivitaId);
239
+
240
+      $nome = $request->get('nome');
241
+      $evento = Evento::create([
242
+        'nome' => $nome,
243
+        'attivita_id' => $attivitaId,
244
+        'is_attivo' => false,
245
+        'codice' => Str::random(30),
246
+      ]);
247
+
248
+      $this->applyDomandePreset($evento, 'pasto');
249
+
250
+      return redirect()->route('evento.edit', ['evento_id' => $evento->id, 'tab' => 'prenotazione']);
251
+    }
252
+
253
+    // ADMIN
254
+    public function applicaPresetDomande(Request $request)
255
+    {
256
+        $request->validate([
257
+            'evento_id' => 'required|exists:evento,id',
258
+            'preset' => 'required|string|in:allergie,orario,bambini,pasto',
259
+        ]);
260
+
261
+        if (! Auth::user()->can('edit-evento') && ! Auth::user()->can('create-evento')) {
262
+            abort(403);
263
+        }
264
+
265
+        $evento = Evento::findOrFail($request->evento_id);
266
+        if(!$evento) return redirect()->route('evento.index')->with('error', 'Evento non trovato');
267
+        AttivitaService::garantisciEventoDiQuestaAttivita($evento);
268
+
269
+        $result = $this->applyDomandePreset($evento, $request->input('preset'));
270
+
271
+        $message = $result['aggiunte'] > 0
272
+            ? "Aggiunte {$result['aggiunte']} domande".($result['saltate'] > 0 ? " ({$result['saltate']} già presenti, saltate)" : '')
273
+            : 'Nessuna domanda aggiunta: risultano già presenti.';
274
+
275
+        return redirect()
276
+            ->route('evento.edit', ['evento_id' => $evento->id, 'tab' => 'prenotazione'])
277
+            ->with('success', $message);
278
+    }
279
+
280
+    // ADMIN
281
+    public function storeDomanda(Request $request)
282
+    {
283
+        $data = $this->validateDomanda($request);
284
+        $evento = Evento::findOrFail($data['evento_id']);
285
+        if(!$evento) return redirect()->route('evento.index')->with('error', 'Evento non trovato');
286
+        AttivitaService::garantisciEventoDiQuestaAttivita($evento);
287
+
288
+        if (! Auth::user()->can('edit-evento') && ! Auth::user()->can('create-evento')) {
289
+            abort(403);
290
+        }
291
+
292
+        DB::transaction(function () use ($evento, $data) {
293
+            $ordine = (int) EventoForm::where('evento_id', $evento->id)->max('ordine_visualizzazione') + 1;
294
+            $form = EventoForm::create([
295
+                'evento_id' => $evento->id,
296
+                'label' => $data['label'],
297
+                'descrizione' => $data['descrizione'] ?? null,
298
+                'tipo' => $data['tipo'],
299
+                'obbligatoria' => (bool) ($data['obbligatoria'] ?? false),
300
+                'per_coperto' => (bool) ($data['per_coperto'] ?? false),
301
+                'nascosta' => false,
302
+                'nascondi_se_auth' => false,
303
+                'ordine_visualizzazione' => $ordine,
304
+            ]);
305
+            $this->syncOpzioniDomanda($form, $data);
306
+        });
307
+
308
+        return redirect()
309
+            ->route('evento.edit', ['evento_id' => $evento->id, 'tab' => 'prenotazione'])
310
+            ->with('success', 'Domanda aggiunta.');
311
+    }
312
+
313
+    // ADMIN
314
+    public function updateDomanda(Request $request, $domanda_id)
315
+    {
316
+        $form = EventoForm::findOrFail($domanda_id);
317
+        if(!$form) return redirect()->route('evento.index')->with('error', 'Domanda non trovata');
318
+        AttivitaService::garantisciEventoDiQuestaAttivita($form->evento);
319
+        
320
+        $data = $this->validateDomanda($request, $form);
321
+
322
+        if (! Auth::user()->can('edit-evento')) {
323
+            abort(403);
324
+        }
325
+
326
+        if ((int) $form->evento_id !== (int) $data['evento_id']) {
327
+            abort(422, 'Domanda non valida per questo evento.');
328
+        }
329
+
330
+        DB::transaction(function () use ($form, $data) {
331
+            $form->update([
332
+                'label' => $data['label'],
333
+                'descrizione' => $data['descrizione'] ?? null,
334
+                'tipo' => $data['tipo'],
335
+                'obbligatoria' => (bool) ($data['obbligatoria'] ?? false),
336
+                'per_coperto' => (bool) ($data['per_coperto'] ?? false),
337
+            ]);
338
+            $this->syncOpzioniDomanda($form, $data);
339
+        });
340
+
341
+        return redirect()
342
+            ->route('evento.edit', ['evento_id' => $form->evento_id, 'tab' => 'prenotazione'])
343
+            ->with('success', 'Domanda aggiornata.');
344
+    }
345
+
346
+    // ADMIN
347
+    public function destroyDomanda(Request $request, $domanda_id)
348
+    {
349
+        $form = EventoForm::findOrFail($domanda_id);
350
+        if(!$form) return redirect()->route('evento.index')->with('error', 'Domanda non trovata');
351
+        AttivitaService::garantisciEventoDiQuestaAttivita($form->evento);
352
+
353
+        if (! Auth::user()->can('edit-evento') && ! Auth::user()->can('delete-evento')) {
354
+            abort(403);
355
+        }
356
+
357
+        $eventoId = $form->evento_id;
358
+        $form->delete(); // cascade su opzioni e risposte
359
+
360
+        return redirect()
361
+            ->route('evento.edit', ['evento_id' => $eventoId, 'tab' => 'prenotazione'])
362
+            ->with('success', 'Domanda eliminata.');
363
+    }
364
+
365
+    // ADMIN
366
+    public function reorderDomande(Request $request)
367
+    {
368
+        $data = $request->validate([
369
+            'evento_id' => 'required|exists:evento,id',
370
+            'ordine' => 'required|array|min:1',
371
+            'ordine.*' => 'integer|exists:evento_form,id',
372
+        ]);
373
+
374
+        if (! Auth::user()->can('edit-evento')) {
375
+            abort(403);
376
+        }
377
+
378
+        $eventoId = (int) $data['evento_id'];
379
+        if(!$eventoId) return redirect()->route('evento.index')->with('error', 'Evento non trovato');
380
+        AttivitaService::garantisciEventoDiQuestaAttivita(Evento::find($eventoId));
381
+        
382
+        $ids = array_map('intval', $data['ordine']);
383
+
384
+        $validIds = EventoForm::where('evento_id', $eventoId)
385
+            ->whereIn('id', $ids)
386
+            ->pluck('id')
387
+            ->map(fn ($id) => (int) $id)
388
+            ->all();
389
+
390
+        if (count($validIds) !== count($ids) || count(array_diff($ids, $validIds)) > 0) {
391
+            return response()->json(['message' => 'Ordine non valido per questo evento.'], 422);
392
+        }
393
+
394
+        DB::transaction(function () use ($ids) {
395
+            foreach ($ids as $index => $id) {
396
+                EventoForm::where('id', $id)->update([
397
+                    'ordine_visualizzazione' => $index + 1,
398
+                ]);
399
+            }
400
+        });
401
+
402
+        return response()->json(['ok' => true]);
403
+    }
404
+
405
+    // ADMIN (helper)
406
+    private function validateDomanda(Request $request, ?EventoForm $existing = null): array
407
+    {
408
+        $tipi = [
409
+            EventoForm::TESTO,
410
+            EventoForm::NUMERO,
411
+            EventoForm::CHECKBOX,
412
+            EventoForm::SELEZIONE,
413
+            EventoForm::MULTISELEZIONE,
414
+        ];
415
+
416
+        return $request->validate([
417
+            'evento_id' => 'required|exists:evento,id',
418
+            'label' => 'required|string|max:255',
419
+            'descrizione' => 'nullable|string|max:1000',
420
+            'tipo' => 'required|in:'.implode(',', $tipi),
421
+            'obbligatoria' => 'nullable|boolean',
422
+            'per_coperto' => 'nullable|boolean',
423
+            'opzioni_testo' => 'nullable|string',
424
+        ]);
425
+    }
426
+
427
+    // ADMIN (helper)
428
+    private function syncOpzioniDomanda(EventoForm $form, array $data): void
429
+    {
430
+        $needsOpzioni = in_array($form->tipo, [EventoForm::SELEZIONE, EventoForm::MULTISELEZIONE], true);
431
+
432
+        if (! $needsOpzioni) {
433
+            OpzioneForm::where('evento_form_id', $form->id)->delete();
434
+            return;
435
+        }
436
+
437
+        $lines = preg_split('/\r\n|\r|\n/', (string) ($data['opzioni_testo'] ?? '')) ?: [];
438
+        $labels = array_values(array_filter(array_map('trim', $lines), fn ($l) => $l !== ''));
439
+
440
+        OpzioneForm::where('evento_form_id', $form->id)->delete();
441
+        foreach ($labels as $i => $label) {
442
+            OpzioneForm::create([
443
+                'evento_form_id' => $form->id,
444
+                'label' => $label,
445
+                'ordine' => $i + 1,
446
+            ]);
447
+        }
448
+    }
449
+
450
+    // ADMIN (helper)
451
+    /**
452
+     * @return array{aggiunte:int,saltate:int}
453
+     */
454
+    private function applyDomandePreset(Evento $evento, string $preset): array
455
+    {
456
+        $definitions = $this->domandePresetDefinitions($preset);
457
+        $aggiunte = 0;
458
+        $saltate = 0;
459
+
460
+        DB::transaction(function () use ($evento, $definitions, &$aggiunte, &$saltate) {
461
+            $ordine = (int) EventoForm::where('evento_id', $evento->id)->max('ordine_visualizzazione');
462
+
463
+            foreach ($definitions as $def) {
464
+                $exists = EventoForm::where('evento_id', $evento->id)
465
+                    ->where('label', $def['label'])
466
+                    ->exists();
467
+
468
+                if ($exists) {
469
+                    $saltate++;
470
+                    continue;
471
+                }
472
+
473
+                $ordine++;
474
+                $form = EventoForm::create([
475
+                    'evento_id' => $evento->id,
476
+                    'label' => $def['label'],
477
+                    'descrizione' => $def['descrizione'] ?? null,
478
+                    'tipo' => $def['tipo'],
479
+                    'obbligatoria' => (bool) ($def['obbligatoria'] ?? false),
480
+                    'nascosta' => false,
481
+                    'nascondi_se_auth' => false,
482
+                    'ordine_visualizzazione' => $ordine,
483
+                ]);
484
+
485
+                foreach ($def['opzioni'] ?? [] as $i => $opzioneLabel) {
486
+                    OpzioneForm::create([
487
+                        'evento_form_id' => $form->id,
488
+                        'label' => $opzioneLabel,
489
+                        'ordine' => $i + 1,
490
+                    ]);
491
+                }
492
+
493
+                $aggiunte++;
494
+            }
495
+        });
496
+
497
+        return ['aggiunte' => $aggiunte, 'saltate' => $saltate];
498
+    }
499
+
500
+    // ADMIN (helper)
501
+    private function domandePresetDefinitions(string $preset): array
502
+    {
503
+        return match ($preset) {
504
+            'allergie' => [
505
+                [
506
+                    'label' => 'Allergie o intolleranze',
507
+                    'descrizione' => 'Indica eventuali allergie o intolleranze alimentari',
508
+                    'tipo' => EventoForm::TESTO,
509
+                    'obbligatoria' => false,
510
+                ],
511
+            ],
512
+            'orario' => [
513
+                [
514
+                    'label' => 'Preferenza orario',
515
+                    'descrizione' => 'Scegli la fascia preferita',
516
+                    'tipo' => EventoForm::SELEZIONE,
517
+                    'obbligatoria' => true,
518
+                    'opzioni' => ['Pranzo', 'Cena'],
519
+                ],
520
+            ],
521
+            'bambini' => [
522
+                [
523
+                    'label' => 'Quanti bambini?',
524
+                    'descrizione' => 'Numero di bambini nel gruppo (0 se nessuno)',
525
+                    'tipo' => EventoForm::NUMERO,
526
+                    'obbligatoria' => false,
527
+                ],
528
+            ],
529
+            'pasto' => [
530
+                [
531
+                    'label' => 'Preferenza orario',
532
+                    'descrizione' => 'Scegli la fascia preferita',
533
+                    'tipo' => EventoForm::SELEZIONE,
534
+                    'obbligatoria' => true,
535
+                    'opzioni' => ['Pranzo', 'Cena'],
536
+                ],
537
+                [
538
+                    'label' => 'Allergie o intolleranze',
539
+                    'descrizione' => 'Indica eventuali allergie o intolleranze alimentari',
540
+                    'tipo' => EventoForm::TESTO,
541
+                    'obbligatoria' => false,
542
+                ],
543
+                [
544
+                    'label' => 'Quanti bambini?',
545
+                    'descrizione' => 'Numero di bambini nel gruppo (0 se nessuno)',
546
+                    'tipo' => EventoForm::NUMERO,
547
+                    'obbligatoria' => false,
548
+                ],
549
+            ],
550
+            default => [],
551
+        };
552
+    }
553
+
554
+    // ADMIN
555
+    public function update(Request $request, $evento_id)
556
+    {
557
+        $evento = Evento::findOrFail($evento_id);
558
+
559
+        if(!$evento) return redirect()->route('evento.index')->with('error', 'Evento non trovato');
560
+        AttivitaService::garantisciEventoDiQuestaAttivita($evento);
561
+
562
+        if (! Auth::user()->can('edit-evento')) {
563
+            abort(403);
564
+        }
565
+
566
+        foreach (['descrizione', 'data_inizio', 'data_fine', 'posti', 'prezzo', 'note', 'apertura_prenotazione', 'chiusura_prenotazione', 'tempo_cortesia_ore', 'luogo', 'luogo_lat', 'luogo_lng'] as $field) {
567
+            if ($request->input($field) === '') {
568
+                $request->merge([$field => null]);
569
+            }
570
+        }
571
+
572
+        $stati = implode(',', array_keys(Evento::stati()));
573
+
574
+        $data = $request->validate([
575
+            'nome' => 'required|string|max:255',
576
+            'descrizione' => 'nullable|string',
577
+            'stato' => 'required|in:'.$stati,
578
+            'is_attivo' => 'nullable|boolean',
579
+            'data_inizio' => 'nullable|date',
580
+            'data_fine' => 'nullable|date|after_or_equal:data_inizio',
581
+            'posti' => 'nullable|integer|min:0',
582
+            'prezzo' => 'nullable|numeric|min:0',
583
+            'prezzo_fisso' => 'nullable|boolean',
584
+            'note' => 'nullable|string',
585
+            'apertura_prenotazione' => 'nullable|date',
586
+            'chiusura_prenotazione' => 'nullable|date|after_or_equal:apertura_prenotazione',
587
+            'tempo_cortesia_ore' => 'nullable|integer|min:0|max:8760',
588
+            'conferma_automatica' => 'nullable|boolean',
589
+            'nascondi_posti_disponibili' => 'nullable|boolean',
590
+            'cliente_modifica_se_confermata' => 'nullable|boolean',
591
+            'cliente_annulla_se_confermata' => 'nullable|boolean',
592
+            'luogo' => 'nullable|string|max:255',
593
+            'luogo_lat' => 'nullable|numeric|between:-90,90',
594
+            'luogo_lng' => 'nullable|numeric|between:-180,180',
595
+            'email_testo_inviata' => 'nullable|string|max:2000',
596
+            'email_testo_confermata' => 'nullable|string|max:2000',
597
+        ]);
598
+
599
+        $data['prezzo_fisso'] = $request->boolean('prezzo_fisso');
600
+        $data['is_attivo'] = $request->boolean('is_attivo');
601
+
602
+        if (! $request->filled('apertura_prenotazione') && ! $request->filled('chiusura_prenotazione')) {
603
+            $data['apertura_prenotazione'] = null;
604
+            $data['chiusura_prenotazione'] = null;
605
+        }
606
+
607
+        $info = is_array($evento->info) ? $evento->info : [];
608
+        $info['tempo_cortesia_ore'] = $request->filled('tempo_cortesia_ore')
609
+            ? (int) $request->input('tempo_cortesia_ore')
610
+            : null;
611
+        $info['conferma_automatica'] = $request->boolean('conferma_automatica');
612
+        $info['nascondi_posti_disponibili'] = $request->boolean('nascondi_posti_disponibili');
613
+        $info['cliente_modifica_se_confermata'] = $request->boolean('cliente_modifica_se_confermata');
614
+        $info['cliente_annulla_se_confermata'] = $request->boolean('cliente_annulla_se_confermata');
615
+        $info['luogo'] = $request->filled('luogo') ? trim((string) $request->input('luogo')) : null;
616
+        if (! $request->filled('luogo')) {
617
+            $info['luogo_lat'] = null;
618
+            $info['luogo_lng'] = null;
619
+        } else {
620
+            $info['luogo_lat'] = $request->filled('luogo_lat') ? (float) $request->input('luogo_lat') : null;
621
+            $info['luogo_lng'] = $request->filled('luogo_lng') ? (float) $request->input('luogo_lng') : null;
622
+        }
623
+
624
+        $testoInviata = trim((string) $request->input('email_testo_inviata', ''));
625
+        $testoConfermata = trim((string) $request->input('email_testo_confermata', ''));
626
+        $info['email_testo_inviata'] = $testoInviata !== '' ? $testoInviata : null;
627
+        $info['email_testo_confermata'] = $testoConfermata !== '' ? $testoConfermata : null;
628
+
629
+        $data['info'] = $info;
630
+
631
+        unset(
632
+            $data['tempo_cortesia_ore'],
633
+            $data['conferma_automatica'],
634
+            $data['nascondi_posti_disponibili'],
635
+            $data['cliente_modifica_se_confermata'],
636
+            $data['cliente_annulla_se_confermata'],
637
+            $data['luogo'],
638
+            $data['luogo_lat'],
639
+            $data['luogo_lng'],
640
+            $data['email_testo_inviata'],
641
+            $data['email_testo_confermata']
642
+        );
643
+
644
+        $evento->update($data);
645
+
646
+        $tab = $request->input('tab', 'generali');
647
+        if (! in_array($tab, ['generali', 'kit', 'prenotazione', 'avanzate', 'email'], true)) {
648
+            $tab = 'generali';
649
+        }
650
+
651
+        return redirect()
652
+            ->route('evento.edit', ['evento_id' => $evento->id, 'tab' => $tab])
653
+            ->with('success', 'Evento aggiornato.');
654
+    }
655
+
656
+    // ADMIN
657
+    public function geocodeLuogo(Request $request)
658
+    {
659
+        if (! Auth::user()->can('edit-evento')) {
660
+            abort(403);
661
+        }
662
+
663
+        $query = trim((string) $request->query('q', ''));
664
+        if (strlen($query) < 3) {
665
+            return response()->json([]);
666
+        }
667
+
668
+        $response = Http::withHeaders([
669
+            'User-Agent' => config('app.name').' ('.config('app.url').')',
670
+        ])->get('https://nominatim.openstreetmap.org/search', [
671
+            'format' => 'json',
672
+            'q' => $query,
673
+            'limit' => 6,
674
+            'addressdetails' => 0,
675
+            'countrycodes' => 'it',
676
+        ]);
677
+
678
+        if (! $response->successful()) {
679
+            return response()->json([]);
680
+        }
681
+
682
+        $results = collect($response->json())
683
+            ->map(fn (array $item) => [
684
+                'label' => $item['display_name'] ?? '',
685
+                'lat' => isset($item['lat']) ? (float) $item['lat'] : null,
686
+                'lng' => isset($item['lon']) ? (float) $item['lon'] : null,
687
+            ])
688
+            ->filter(fn (array $item) => filled($item['label']))
689
+            ->values();
690
+
691
+        return response()->json($results);
692
+    }
693
+
694
+    // ADMIN
695
+    public function uploadLocandina(Request $request, $evento_id)
696
+    {
697
+        return $this->uploadImmagineEvento($request, $evento_id, 'locandina', 'immagine', 'Locandina aggiornata.');
698
+    }
699
+
700
+    // ADMIN
701
+    public function destroyLocandina(Request $request, $evento_id)
702
+    {
703
+        return $this->destroyImmagineEvento($evento_id, 'immagine', 'Locandina rimossa.');
704
+    }
705
+
706
+    // ADMIN
707
+    public function uploadCopertina(Request $request, $evento_id)
708
+    {
709
+        return $this->uploadImmagineEvento($request, $evento_id, 'copertina', 'copertina', 'Copertina aggiornata.');
710
+    }
711
+
712
+    // ADMIN
713
+    public function destroyCopertina(Request $request, $evento_id)
714
+    {
715
+        return $this->destroyImmagineEvento($evento_id, 'copertina', 'Copertina rimossa.');
716
+    }
717
+
718
+    // ADMIN (helper)
719
+    private function uploadImmagineEvento(Request $request, $evento_id, string $inputName, string $column, string $message)
720
+    {
721
+        $evento = Evento::findOrFail($evento_id);
722
+        if(!$evento) return redirect()->route('evento.index')->with('error', 'Evento non trovato');
723
+        AttivitaService::garantisciEventoDiQuestaAttivita($evento);
724
+        
725
+        if (! Auth::user()->can('edit-evento')) {
726
+            abort(403);
727
+        }
728
+
729
+        $request->validate([
730
+            $inputName => 'required|file|image|mimes:jpeg,png,jpg,gif,webp|max:5120',
731
+        ]);
732
+
733
+        $disk = Storage::disk('eventi');
734
+        $dir = (string) $evento->id;
735
+        $ext = strtolower($request->file($inputName)->getClientOriginalExtension() ?: 'jpg');
736
+        // Nome univoco: evita cache browser sulla stessa URL dopo sostituzione
737
+        $filename = $column.'_'.time().'_'.Str::random(4).'.'.$ext;
738
+        $path = $dir.'/'.$filename;
739
+
740
+        $oldPath = $evento->{$column};
741
+        if (filled($oldPath) && $disk->exists($oldPath)) {
742
+            $disk->delete($oldPath);
743
+        }
744
+
745
+        $disk->makeDirectory($dir);
746
+        $disk->putFileAs($dir, $request->file($inputName), $filename);
747
+
748
+        $evento->{$column} = $path;
749
+        $evento->save();
750
+
751
+        return redirect()
752
+            ->route('evento.edit', ['evento_id' => $evento->id, 'tab' => 'kit'])
753
+            ->with('success', $message);
754
+    }
755
+
756
+    // ADMIN (helper)
757
+    private function destroyImmagineEvento($evento_id, string $column, string $message)
758
+    {
759
+        $evento = Evento::findOrFail($evento_id);
760
+        if(!$evento) return redirect()->route('evento.index')->with('error', 'Evento non trovato');
761
+        AttivitaService::garantisciEventoDiQuestaAttivita($evento);
762
+        
763
+        if (! Auth::user()->can('edit-evento') && ! Auth::user()->can('delete-evento')) {
764
+            abort(403);
765
+        }
766
+
767
+        $disk = Storage::disk('eventi');
768
+        if (filled($evento->{$column}) && $disk->exists($evento->{$column})) {
769
+            $disk->delete($evento->{$column});
770
+        }
771
+
772
+        $evento->{$column} = null;
773
+        $evento->save();
774
+
775
+        return redirect()
776
+            ->route('evento.edit', ['evento_id' => $evento->id, 'tab' => 'kit'])
777
+            ->with('success', $message);
778
+    }
96 779
 }

+ 2
- 0
app/Http/Controllers/EventoFormController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\EventoForm;
7 9
 use App\Models\Evento;

+ 834
- 0
app/Http/Controllers/EventoPiantinaController.php Просмотреть файл

@@ -0,0 +1,834 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use App\Models\Evento;
6
+use App\Models\EventoSala;
7
+use App\Models\EventoTavolo;
8
+use App\Models\Prenotazione;
9
+use App\Models\PrenotazioneAssegnazioneTavolo;
10
+use App\Services\Attivita\AttivitaService;
11
+use App\Services\Prenotazione\AssegnaTavoliAutomatico;
12
+use Illuminate\Http\Request;
13
+use Illuminate\Routing\Controllers\Middleware;
14
+use Illuminate\Support\Facades\Storage;
15
+use Illuminate\Support\Str;
16
+
17
+class EventoPiantinaController extends Controller
18
+{
19
+    public static function middleware(): array
20
+    {
21
+        return [
22
+            new Middleware('permission:view-evento', only: ['edit', 'assegnazioni']),
23
+            new Middleware('permission:edit-evento', only: [
24
+                'storeSala',
25
+                'updateSala',
26
+                'destroySala',
27
+                'uploadPiantina',
28
+                'destroyPiantina',
29
+                'storeTavolo',
30
+                'updateTavolo',
31
+                'destroyTavolo',
32
+                'batchTavoli',
33
+                'assegna',
34
+                'assegnaAutomatico',
35
+                'rimuoviAssegnazione',
36
+            ]),
37
+        ];
38
+    }
39
+
40
+    /**
41
+     * Editor piantina (sala + tavoli).
42
+     */
43
+    public function edit(Request $request)
44
+    {
45
+        $evento = $this->findEventoOrFail($request->get('evento_id'));
46
+        $sale = $this->saleList($evento);
47
+        $sala = $this->resolveSala($request, $evento, $sale);
48
+        $sala->load(['tavoli' => fn ($q) => $q->orderBy('ordine_in_gruppo')->orderBy('label')]);
49
+
50
+        return view('evento.piantina.edit', [
51
+            'evento' => $evento,
52
+            'sala' => $sala,
53
+            'sale' => $sale,
54
+            'piantinaUrl' => $this->piantinaUrl($sala),
55
+            'griglia' => $sala->grigliaConfig(),
56
+        ]);
57
+    }
58
+
59
+    /**
60
+     * Crea una nuova sala/zona per l'evento.
61
+     */
62
+    public function storeSala(Request $request, int $evento_id)
63
+    {
64
+        $evento = $this->findEventoOrFail($evento_id);
65
+        $data = $request->validate([
66
+            'nome' => 'nullable|string|max:255',
67
+        ]);
68
+
69
+        $ordine = (int) $evento->sale()->max('ordine');
70
+        $sala = EventoSala::create([
71
+            'evento_id' => $evento->id,
72
+            'nome' => filled($data['nome'] ?? null) ? trim($data['nome']) : 'Nuova sala',
73
+            'ordine' => $ordine + 1,
74
+        ]);
75
+
76
+        return redirect()
77
+            ->route('evento.piantina.edit', $this->piantinaParams($evento, $sala))
78
+            ->with('success', 'Sala creata.');
79
+    }
80
+
81
+    /**
82
+     * Aggiorna metadati sala (nome, dimensioni).
83
+     */
84
+    public function updateSala(Request $request, int $evento_id)
85
+    {
86
+        $evento = $this->findEventoOrFail($evento_id);
87
+        $sala = $this->resolveSala($request, $evento);
88
+
89
+        $data = $request->validate([
90
+            'nome' => 'sometimes|nullable|string|max:255',
91
+            'larghezza' => 'sometimes|nullable|integer|min:1|max:20000',
92
+            'altezza' => 'sometimes|nullable|integer|min:1|max:20000',
93
+            'griglia_attiva' => 'nullable|boolean',
94
+            'griglia_modalita' => 'nullable|string|in:celle,libera',
95
+            'griglia_cols' => 'nullable|integer|min:1|max:40',
96
+            'griglia_rows' => 'nullable|integer|min:1|max:40',
97
+            'griglia_margin_top' => 'nullable|numeric|between:0,40',
98
+            'griglia_margin_right' => 'nullable|numeric|between:0,40',
99
+            'griglia_margin_bottom' => 'nullable|numeric|between:0,40',
100
+            'griglia_margin_left' => 'nullable|numeric|between:0,40',
101
+            'griglia_inset' => 'nullable|numeric|between:0,40',
102
+            'griglia_inset_v' => 'nullable|numeric|between:0,40',
103
+            'griglia_colonne' => 'nullable|string|max:255',
104
+        ]);
105
+
106
+        if ($request->exists('nome')) {
107
+            $sala->nome = filled($data['nome'] ?? null) ? trim($data['nome']) : null;
108
+        }
109
+        if ($request->exists('larghezza')) {
110
+            $sala->larghezza = $data['larghezza'] ?? null;
111
+        }
112
+        if ($request->exists('altezza')) {
113
+            $sala->altezza = $data['altezza'] ?? null;
114
+        }
115
+
116
+        $info = is_array($sala->info) ? $sala->info : [];
117
+        $prev = is_array($info['griglia'] ?? null) ? $info['griglia'] : [];
118
+        $modalita = $data['griglia_modalita'] ?? ($prev['modalita'] ?? 'libera');
119
+        if (! in_array($modalita, ['celle', 'libera'], true)) {
120
+            $modalita = 'libera';
121
+        }
122
+
123
+        $attiva = $request->exists('griglia_attiva')
124
+            ? $request->boolean('griglia_attiva')
125
+            : (bool) ($prev['attiva'] ?? ($modalita === 'celle'));
126
+
127
+        $info['griglia'] = [
128
+            'attiva' => $attiva,
129
+            'modalita' => $modalita,
130
+            'cols' => (int) ($data['griglia_cols'] ?? ($prev['cols'] ?? 10)),
131
+            'rows' => (int) ($data['griglia_rows'] ?? ($prev['rows'] ?? 4)),
132
+            'margin_top' => (float) ($data['griglia_margin_top'] ?? ($prev['margin_top'] ?? 14)),
133
+            'margin_right' => (float) ($data['griglia_margin_right'] ?? ($prev['margin_right'] ?? 2)),
134
+            'margin_bottom' => (float) ($data['griglia_margin_bottom'] ?? ($prev['margin_bottom'] ?? 2)),
135
+            'margin_left' => (float) ($data['griglia_margin_left'] ?? ($prev['margin_left'] ?? 8)),
136
+            'inset' => (float) ($data['griglia_inset'] ?? ($prev['inset'] ?? 6)),
137
+            'inset_v' => (float) ($data['griglia_inset_v'] ?? ($prev['inset_v'] ?? 1.5)),
138
+            'colonne' => trim((string) ($data['griglia_colonne'] ?? ($prev['colonne'] ?? 'A,B,C,D,E,F,H,K,P,R'))),
139
+        ];
140
+        $sala->info = $info;
141
+        $sala->save();
142
+
143
+        if ($request->expectsJson() || $request->wantsJson()) {
144
+            return response()->json([
145
+                'ok' => true,
146
+                'griglia' => $sala->grigliaConfig(),
147
+            ]);
148
+        }
149
+
150
+        return redirect()
151
+            ->route('evento.piantina.edit', $this->piantinaParams($evento, $sala))
152
+            ->with('success', 'Sala e griglia aggiornate.');
153
+    }
154
+
155
+    /**
156
+     * Elimina una sala (non l'ultima).
157
+     */
158
+    public function destroySala(Request $request, int $evento_id, int $sala_id)
159
+    {
160
+        $evento = $this->findEventoOrFail($evento_id);
161
+        $sala = $evento->sale()->where('id', $sala_id)->firstOrFail();
162
+
163
+        if ($evento->sale()->count() <= 1) {
164
+            return redirect()
165
+                ->route('evento.piantina.edit', $this->piantinaParams($evento, $sala))
166
+                ->with('error', 'Non puoi eliminare l’unica sala dell’evento.');
167
+        }
168
+
169
+        $disk = Storage::disk('eventi');
170
+        if (filled($sala->immagine) && $disk->exists($sala->immagine)) {
171
+            $disk->delete($sala->immagine);
172
+        }
173
+        $sala->delete();
174
+
175
+        $next = $this->ensureSala($evento);
176
+
177
+        return redirect()
178
+            ->route('evento.piantina.edit', $this->piantinaParams($evento, $next))
179
+            ->with('success', 'Sala eliminata.');
180
+    }
181
+
182
+    /**
183
+     * Upload immagine piantina.
184
+     */
185
+    public function uploadPiantina(Request $request, int $evento_id)
186
+    {
187
+        $evento = $this->findEventoOrFail($evento_id);
188
+        $sala = $this->resolveSala($request, $evento);
189
+
190
+        $request->validate([
191
+            'immagine' => 'required|file|image|mimes:jpeg,png,jpg,gif,webp|max:8192',
192
+        ]);
193
+
194
+        $disk = Storage::disk('eventi');
195
+        $dir = $evento->id.'/piantina';
196
+        $ext = strtolower($request->file('immagine')->getClientOriginalExtension() ?: 'jpg');
197
+        $filename = 'piantina_'.time().'_'.Str::random(4).'.'.$ext;
198
+        $path = $dir.'/'.$filename;
199
+
200
+        if (filled($sala->immagine) && $disk->exists($sala->immagine)) {
201
+            $disk->delete($sala->immagine);
202
+        }
203
+
204
+        $disk->makeDirectory($dir);
205
+        $disk->putFileAs($dir, $request->file('immagine'), $filename);
206
+
207
+        $sala->immagine = $path;
208
+
209
+        // Dimensioni naturali se non impostate
210
+        $full = $disk->path($path);
211
+        if (is_file($full) && (! $sala->larghezza || ! $sala->altezza)) {
212
+            $size = @getimagesize($full);
213
+            if (is_array($size)) {
214
+                $sala->larghezza = $sala->larghezza ?: (int) $size[0];
215
+                $sala->altezza = $sala->altezza ?: (int) $size[1];
216
+            }
217
+        }
218
+
219
+        $sala->save();
220
+
221
+        return redirect()
222
+            ->route('evento.piantina.edit', $this->piantinaParams($evento, $sala))
223
+            ->with('success', 'Piantina caricata.');
224
+    }
225
+
226
+    public function destroyPiantina(Request $request, int $evento_id)
227
+    {
228
+        $evento = $this->findEventoOrFail($evento_id);
229
+        $sala = $this->resolveSala($request, $evento);
230
+
231
+        $disk = Storage::disk('eventi');
232
+        if (filled($sala->immagine) && $disk->exists($sala->immagine)) {
233
+            $disk->delete($sala->immagine);
234
+        }
235
+
236
+        $sala->immagine = null;
237
+        $sala->save();
238
+
239
+        return redirect()
240
+            ->route('evento.piantina.edit', $this->piantinaParams($evento, $sala))
241
+            ->with('success', 'Piantina rimossa.');
242
+    }
243
+
244
+    /**
245
+     * Crea un tavolo sulla piantina.
246
+     */
247
+    public function storeTavolo(Request $request, int $evento_id)
248
+    {
249
+        $evento = $this->findEventoOrFail($evento_id);
250
+        $sala = $this->resolveSala($request, $evento);
251
+
252
+        $data = $request->validate([
253
+            'label' => 'required|string|max:50',
254
+            'posti' => 'required|integer|min:1|max:200',
255
+            'x' => 'nullable|numeric|between:0,100',
256
+            'y' => 'nullable|numeric|between:0,100',
257
+            'w' => 'nullable|numeric|between:0.5,100',
258
+            'h' => 'nullable|numeric|between:0.5,100',
259
+            'rotazione' => 'nullable|integer|between:-360,360',
260
+            'forma' => 'nullable|string|in:rettangolo,cerchio',
261
+            'gruppo_id' => 'nullable|string|max:100',
262
+            'ordine_in_gruppo' => 'nullable|integer|min:0|max:9999',
263
+            'is_attivo' => 'nullable|boolean',
264
+        ]);
265
+
266
+        $tavolo = EventoTavolo::create([
267
+            'evento_sala_id' => $sala->id,
268
+            'label' => trim($data['label']),
269
+            'posti' => (int) $data['posti'],
270
+            'x' => (float) ($data['x'] ?? 10),
271
+            'y' => (float) ($data['y'] ?? 10),
272
+            'w' => (float) ($data['w'] ?? 8),
273
+            'h' => (float) ($data['h'] ?? 8),
274
+            'rotazione' => (int) ($data['rotazione'] ?? 0),
275
+            'forma' => $data['forma'] ?? EventoTavolo::FORMA_RETTANGOLO,
276
+            'gruppo_id' => filled($data['gruppo_id'] ?? null) ? trim($data['gruppo_id']) : null,
277
+            'ordine_in_gruppo' => (int) ($data['ordine_in_gruppo'] ?? 0),
278
+            'is_attivo' => $request->boolean('is_attivo', true),
279
+        ]);
280
+
281
+        if ($request->expectsJson() || $request->wantsJson()) {
282
+            return response()->json(['ok' => true, 'tavolo' => $tavolo]);
283
+        }
284
+
285
+        return redirect()
286
+            ->route('evento.piantina.edit', $this->piantinaParams($evento, $sala))
287
+            ->with('success', 'Tavolo '.$tavolo->label.' aggiunto.');
288
+    }
289
+
290
+    /**
291
+     * Aggiorna tavolo (posizione, posti, gruppo…).
292
+     */
293
+    public function updateTavolo(Request $request, int $evento_id, int $tavolo_id)
294
+    {
295
+        $evento = $this->findEventoOrFail($evento_id);
296
+        $sala = $this->resolveSala($request, $evento);
297
+        $tavolo = EventoTavolo::where('evento_sala_id', $sala->id)->findOrFail($tavolo_id);
298
+
299
+        $data = $request->validate([
300
+            'label' => 'sometimes|required|string|max:50',
301
+            'posti' => 'sometimes|required|integer|min:1|max:200',
302
+            'x' => 'nullable|numeric|between:0,100',
303
+            'y' => 'nullable|numeric|between:0,100',
304
+            'w' => 'nullable|numeric|between:0.5,100',
305
+            'h' => 'nullable|numeric|between:0.5,100',
306
+            'rotazione' => 'nullable|integer|between:-360,360',
307
+            'forma' => 'nullable|string|in:rettangolo,cerchio',
308
+            'gruppo_id' => 'nullable|string|max:100',
309
+            'ordine_in_gruppo' => 'nullable|integer|min:0|max:9999',
310
+            'is_attivo' => 'nullable|boolean',
311
+        ]);
312
+
313
+        if (array_key_exists('label', $data)) {
314
+            $tavolo->label = trim($data['label']);
315
+        }
316
+        if (array_key_exists('posti', $data)) {
317
+            $tavolo->posti = (int) $data['posti'];
318
+        }
319
+        foreach (['x', 'y', 'w', 'h'] as $coord) {
320
+            if (array_key_exists($coord, $data) && $data[$coord] !== null) {
321
+                $tavolo->{$coord} = (float) $data[$coord];
322
+            }
323
+        }
324
+        if (array_key_exists('rotazione', $data) && $data['rotazione'] !== null) {
325
+            $tavolo->rotazione = (int) $data['rotazione'];
326
+        }
327
+        if (array_key_exists('forma', $data) && $data['forma'] !== null) {
328
+            $tavolo->forma = $data['forma'];
329
+        }
330
+        if (array_key_exists('gruppo_id', $data)) {
331
+            $tavolo->gruppo_id = filled($data['gruppo_id']) ? trim($data['gruppo_id']) : null;
332
+        }
333
+        if (array_key_exists('ordine_in_gruppo', $data) && $data['ordine_in_gruppo'] !== null) {
334
+            $tavolo->ordine_in_gruppo = (int) $data['ordine_in_gruppo'];
335
+        }
336
+        if ($request->has('is_attivo')) {
337
+            $tavolo->is_attivo = $request->boolean('is_attivo');
338
+        }
339
+
340
+        $tavolo->save();
341
+
342
+        if ($request->expectsJson() || $request->wantsJson()) {
343
+            return response()->json(['ok' => true, 'tavolo' => $tavolo->fresh()]);
344
+        }
345
+
346
+        return redirect()
347
+            ->route('evento.piantina.edit', $this->piantinaParams($evento, $sala))
348
+            ->with('success', 'Tavolo aggiornato.');
349
+    }
350
+
351
+    public function destroyTavolo(Request $request, int $evento_id, int $tavolo_id)
352
+    {
353
+        $evento = $this->findEventoOrFail($evento_id);
354
+        $sala = $this->resolveSala($request, $evento);
355
+        $tavolo = EventoTavolo::where('evento_sala_id', $sala->id)->findOrFail($tavolo_id);
356
+        $label = $tavolo->label;
357
+        $tavolo->delete();
358
+
359
+        if ($request->expectsJson() || $request->wantsJson()) {
360
+            return response()->json(['ok' => true]);
361
+        }
362
+
363
+        return redirect()
364
+            ->route('evento.piantina.edit', $this->piantinaParams($evento, $sala))
365
+            ->with('success', 'Tavolo '.$label.' eliminato.');
366
+    }
367
+
368
+    /**
369
+     * Aggiorna geometria/label di più tavoli in un colpo (allinea griglia).
370
+     */
371
+    public function batchTavoli(Request $request, int $evento_id)
372
+    {
373
+        $evento = $this->findEventoOrFail($evento_id);
374
+        $sala = $this->resolveSala($request, $evento);
375
+
376
+        $data = $request->validate([
377
+            'tavoli' => 'required|array|min:1|max:200',
378
+            'tavoli.*.id' => 'required|integer',
379
+            'tavoli.*.x' => 'nullable|numeric|between:0,100',
380
+            'tavoli.*.y' => 'nullable|numeric|between:0,100',
381
+            'tavoli.*.w' => 'nullable|numeric|between:0.5,100',
382
+            'tavoli.*.h' => 'nullable|numeric|between:0.5,100',
383
+            'tavoli.*.label' => 'nullable|string|max:50',
384
+            'tavoli.*.posti' => 'nullable|integer|min:1|max:200',
385
+            'tavoli.*.gruppo_id' => 'nullable|string|max:100',
386
+            'tavoli.*.ordine_in_gruppo' => 'nullable|integer|min:0|max:9999',
387
+        ]);
388
+
389
+        $ids = collect($data['tavoli'])->pluck('id')->map(fn ($id) => (int) $id)->all();
390
+        $existing = EventoTavolo::query()
391
+            ->where('evento_sala_id', $sala->id)
392
+            ->whereIn('id', $ids)
393
+            ->get()
394
+            ->keyBy('id');
395
+
396
+        $updated = [];
397
+        foreach ($data['tavoli'] as $row) {
398
+            $tavolo = $existing->get((int) $row['id']);
399
+            if (! $tavolo) {
400
+                continue;
401
+            }
402
+            foreach (['x', 'y', 'w', 'h'] as $coord) {
403
+                if (array_key_exists($coord, $row) && $row[$coord] !== null) {
404
+                    $tavolo->{$coord} = (float) $row[$coord];
405
+                }
406
+            }
407
+            if (array_key_exists('label', $row) && filled($row['label'])) {
408
+                $tavolo->label = trim($row['label']);
409
+            }
410
+            if (array_key_exists('posti', $row) && $row['posti'] !== null) {
411
+                $tavolo->posti = (int) $row['posti'];
412
+            }
413
+            if (array_key_exists('gruppo_id', $row)) {
414
+                $tavolo->gruppo_id = filled($row['gruppo_id']) ? trim($row['gruppo_id']) : null;
415
+            }
416
+            if (array_key_exists('ordine_in_gruppo', $row) && $row['ordine_in_gruppo'] !== null) {
417
+                $tavolo->ordine_in_gruppo = (int) $row['ordine_in_gruppo'];
418
+            }
419
+            $tavolo->save();
420
+            $updated[] = $tavolo->fresh();
421
+        }
422
+
423
+        return response()->json(['ok' => true, 'tavoli' => $updated]);
424
+    }
425
+
426
+    /**
427
+     * Vista assegnazione prenotazioni → tavoli.
428
+     */
429
+    public function assegnazioni(Request $request)
430
+    {
431
+        $evento = $this->findEventoOrFail($request->get('evento_id'));
432
+        $sale = $this->saleList($evento);
433
+        $sala = $this->resolveSala($request, $evento, $sale);
434
+        $sala->load([
435
+            'tavoli' => fn ($q) => $q->where('is_attivo', true)
436
+                ->with(['assegnazioni.prenotazione'])
437
+                ->orderBy('ordine_in_gruppo')
438
+                ->orderBy('label'),
439
+        ]);
440
+
441
+        $prenotazioni = Prenotazione::query()
442
+            ->where('evento_id', $evento->id)
443
+            ->whereNotIn('stato', [
444
+                Prenotazione::STATO_CANCELLATA,
445
+                Prenotazione::STATO_ANNULLATA,
446
+                Prenotazione::STATO_RIFIUTATA,
447
+            ])
448
+            ->with(['assegnazioniTavolo.eventoTavolo'])
449
+            ->orderByDesc('confermata')
450
+            ->orderBy('cognome')
451
+            ->orderBy('nome')
452
+            ->get();
453
+
454
+        $tavoliJs = $sala->tavoli->map(function (EventoTavolo $t) {
455
+            $occupati = $t->postiOccupati();
456
+
457
+            return [
458
+                'id' => $t->id,
459
+                'label' => $t->label,
460
+                'posti' => (int) $t->posti,
461
+                'occupati' => $occupati,
462
+                'liberi' => max(0, (int) $t->posti - $occupati),
463
+                'x' => (float) $t->x,
464
+                'y' => (float) $t->y,
465
+                'w' => (float) $t->w,
466
+                'h' => (float) $t->h,
467
+                'forma' => $t->forma ?: 'rettangolo',
468
+                'gruppo_id' => $t->gruppo_id,
469
+                'assegnazioni' => $t->assegnazioni->map(fn ($a) => [
470
+                    'id' => $a->id,
471
+                    'posti' => (int) $a->posti_assegnati,
472
+                    'prenotazione_id' => (int) $a->prenotazione_id,
473
+                    'nome' => trim(($a->prenotazione?->cognome ?? '').' '.($a->prenotazione?->nome ?? '')),
474
+                    'codice' => $a->prenotazione?->codice,
475
+                ])->values(),
476
+            ];
477
+        })->values();
478
+
479
+        $prenotazioniJs = $prenotazioni->map(function (Prenotazione $p) {
480
+            $coperti = max(1, (int) ($p->numero_persone ?? 1));
481
+            $assegnati = (int) $p->assegnazioniTavolo->sum('posti_assegnati');
482
+
483
+            return [
484
+                'id' => $p->id,
485
+                'nome' => trim(($p->cognome ?? '').' '.($p->nome ?? '')),
486
+                'codice' => $p->codice,
487
+                'stato' => $p->stato,
488
+                'confermata' => (bool) $p->confermata,
489
+                'coperti' => $coperti,
490
+                'assegnati' => $assegnati,
491
+                'rimasti' => max(0, $coperti - $assegnati),
492
+                'assegnazioni' => $p->assegnazioniTavolo->map(fn ($a) => [
493
+                    'id' => $a->id,
494
+                    'posti' => (int) $a->posti_assegnati,
495
+                    'tavolo_id' => (int) $a->evento_tavolo_id,
496
+                    'label' => $a->eventoTavolo?->label,
497
+                    'gruppo_id' => $a->eventoTavolo?->gruppo_id,
498
+                ])->values(),
499
+            ];
500
+        })->values();
501
+
502
+        return view('evento.piantina.assegnazioni', [
503
+            'evento' => $evento,
504
+            'sala' => $sala,
505
+            'sale' => $sale,
506
+            'prenotazioni' => $prenotazioni,
507
+            'piantinaUrl' => $this->piantinaUrl($sala),
508
+            'tavoliJs' => $tavoliJs,
509
+            'prenotazioniJs' => $prenotazioniJs,
510
+            'griglia' => $sala->grigliaConfig(),
511
+        ]);
512
+    }
513
+
514
+    /**
515
+     * Assegna automaticamente le prenotazioni ai tavoli (intere + buchi + spezza colonna).
516
+     */
517
+    public function assegnaAutomatico(Request $request, int $evento_id, AssegnaTavoliAutomatico $service)
518
+    {
519
+        $evento = $this->findEventoOrFail($evento_id);
520
+        $sala = $this->resolveSala($request, $evento);
521
+
522
+        $data = $request->validate([
523
+            'solo_confermate' => 'nullable|boolean',
524
+        ]);
525
+
526
+        $stats = $service->esegui($evento, $sala, [
527
+            'solo_confermate' => $request->boolean('solo_confermate'),
528
+        ]);
529
+
530
+        $msg = sprintf(
531
+            'Assegnazione automatica: %d posti su %d prenotazioni (%d intere, %d nei buchi, %d spezzate).',
532
+            $stats['posti_assegnati'],
533
+            $stats['prenotazioni_toccate'],
534
+            $stats['intere'],
535
+            $stats['buchi'],
536
+            $stats['spezzate']
537
+        );
538
+        if ($stats['non_collocate'] > 0) {
539
+            $msg .= ' '.$stats['non_collocate'].' ancora senza posto completo.';
540
+        }
541
+
542
+        if ($request->expectsJson() || $request->wantsJson()) {
543
+            return response()->json([
544
+                'ok' => true,
545
+                'message' => $msg,
546
+                'stats' => $stats,
547
+            ]);
548
+        }
549
+
550
+        return redirect()
551
+            ->route('evento.piantina.assegnazioni', $this->piantinaParams($evento, $sala))
552
+            ->with('success', $msg);
553
+    }
554
+
555
+    /**
556
+     * Assegna posti di una prenotazione a un tavolo (eventualmente spezzati).
557
+     */
558
+    public function assegna(Request $request, int $evento_id)
559
+    {
560
+        $evento = $this->findEventoOrFail($evento_id);
561
+        $sala = $this->resolveSala($request, $evento);
562
+
563
+        $data = $request->validate([
564
+            'prenotazione_id' => 'required|integer|exists:prenotazione,id',
565
+            'evento_tavolo_id' => 'required|integer|exists:evento_tavolo,id',
566
+            'posti_assegnati' => 'nullable|integer|min:1|max:200',
567
+        ]);
568
+
569
+        $prenotazione = Prenotazione::where('evento_id', $evento->id)->findOrFail($data['prenotazione_id']);
570
+        $tavolo = EventoTavolo::where('evento_sala_id', $sala->id)->findOrFail($data['evento_tavolo_id']);
571
+
572
+        if (in_array($prenotazione->stato, [
573
+            Prenotazione::STATO_CANCELLATA,
574
+            Prenotazione::STATO_ANNULLATA,
575
+            Prenotazione::STATO_RIFIUTATA,
576
+        ], true)) {
577
+            return $this->assegnazioneFail($request, $evento, 'Prenotazione non assegnabile in questo stato.', $sala);
578
+        }
579
+
580
+        $coperti = max(1, (int) ($prenotazione->numero_persone ?? 1));
581
+        $giaAssegnati = (int) $prenotazione->assegnazioniTavolo()->sum('posti_assegnati');
582
+        $rimanenti = max(0, $coperti - $giaAssegnati);
583
+        if ($rimanenti < 1) {
584
+            return $this->assegnazioneFail($request, $evento, 'Tutti i coperti di questa prenotazione sono già assegnati.', $sala);
585
+        }
586
+
587
+        $postiRichiesti = (int) ($data['posti_assegnati'] ?? $rimanenti);
588
+        $postiRichiesti = min(max(1, $postiRichiesti), $rimanenti);
589
+
590
+        // Se spezza su un secondo tavolo, deve essere dello stesso gruppo (tavoli attaccati)
591
+        $esistenti = $prenotazione->assegnazioniTavolo()->with('eventoTavolo')->get();
592
+        if ($esistenti->isNotEmpty()) {
593
+            $okVicino = $esistenti->contains(function (PrenotazioneAssegnazioneTavolo $a) use ($tavolo) {
594
+                $t = $a->eventoTavolo;
595
+                if (! $t) {
596
+                    return false;
597
+                }
598
+                if ((int) $t->id === (int) $tavolo->id) {
599
+                    return true;
600
+                }
601
+                if (! filled($t->gruppo_id) || ! filled($tavolo->gruppo_id)) {
602
+                    return false;
603
+                }
604
+
605
+                return $t->gruppo_id === $tavolo->gruppo_id
606
+                    && (int) $t->evento_sala_id === (int) $tavolo->evento_sala_id;
607
+            });
608
+
609
+            if (! $okVicino) {
610
+                return $this->assegnazioneFail(
611
+                    $request,
612
+                    $evento,
613
+                    'Per spezzare i coperti usa un tavolo dello stesso gruppo (tavoli attaccati).',
614
+                    $sala
615
+                );
616
+            }
617
+        }
618
+
619
+        $assegnazione = PrenotazioneAssegnazioneTavolo::firstOrNew([
620
+            'prenotazione_id' => $prenotazione->id,
621
+            'evento_tavolo_id' => $tavolo->id,
622
+        ]);
623
+
624
+        $giaSuQuesto = $assegnazione->exists ? (int) $assegnazione->posti_assegnati : 0;
625
+        $altriSuQuesto = (int) $tavolo->assegnazioni()
626
+            ->when($assegnazione->exists, fn ($q) => $q->where('id', '!=', $assegnazione->id))
627
+            ->sum('posti_assegnati');
628
+        $liberiPerQuesta = max(0, (int) $tavolo->posti - $altriSuQuesto - $giaSuQuesto);
629
+        $aggiungi = min($postiRichiesti, $liberiPerQuesta);
630
+
631
+        if ($aggiungi < 1) {
632
+            return $this->assegnazioneFail($request, $evento, 'Il tavolo non ha posti liberi sufficienti.', $sala);
633
+        }
634
+
635
+        $assegnazione->posti_assegnati = $giaSuQuesto + $aggiungi;
636
+        if (! $assegnazione->exists) {
637
+            $assegnazione->ordine = (int) ($esistenti->max('ordine') ?? -1) + 1;
638
+        }
639
+        $assegnazione->save();
640
+
641
+        if ($request->expectsJson() || $request->wantsJson()) {
642
+            return response()->json([
643
+                'ok' => true,
644
+                'aggiunti' => $aggiungi,
645
+                'assegnazione' => $assegnazione->fresh(['eventoTavolo', 'prenotazione']),
646
+                'tavolo' => $this->tavoloPayload($tavolo->fresh(['assegnazioni.prenotazione'])),
647
+                'prenotazione' => $this->prenotazionePayload($prenotazione->fresh(['assegnazioniTavolo.eventoTavolo'])),
648
+            ]);
649
+        }
650
+
651
+        return redirect()
652
+            ->route('evento.piantina.assegnazioni', $this->piantinaParams($evento, $sala))
653
+            ->with('success', 'Assegnati '.$aggiungi.' posti a '.$tavolo->label.'.');
654
+    }
655
+
656
+    public function rimuoviAssegnazione(Request $request, int $evento_id, int $assegnazione_id)
657
+    {
658
+        $evento = $this->findEventoOrFail($evento_id);
659
+        $sala = $this->resolveSala($request, $evento);
660
+
661
+        $assegnazione = PrenotazioneAssegnazioneTavolo::query()
662
+            ->whereKey($assegnazione_id)
663
+            ->whereHas('prenotazione', fn ($q) => $q->where('evento_id', $evento->id))
664
+            ->firstOrFail();
665
+
666
+        $prenotazione = $assegnazione->prenotazione;
667
+        $tavolo = $assegnazione->eventoTavolo;
668
+        $assegnazione->delete();
669
+
670
+        if ($tavolo && ! $tavolo->relationLoaded('assegnazioni')) {
671
+            $tavolo->load(['assegnazioni.prenotazione']);
672
+        }
673
+        if ($prenotazione && ! $prenotazione->relationLoaded('assegnazioniTavolo')) {
674
+            $prenotazione->load(['assegnazioniTavolo.eventoTavolo']);
675
+        }
676
+
677
+        if ($request->expectsJson() || $request->wantsJson()) {
678
+            return response()->json([
679
+                'ok' => true,
680
+                'tavolo' => $tavolo ? $this->tavoloPayload($tavolo->fresh(['assegnazioni.prenotazione'])) : null,
681
+                'prenotazione' => $prenotazione ? $this->prenotazionePayload($prenotazione->fresh(['assegnazioniTavolo.eventoTavolo'])) : null,
682
+            ]);
683
+        }
684
+
685
+        return redirect()
686
+            ->route('evento.piantina.assegnazioni', $this->piantinaParams($evento, $sala))
687
+            ->with('success', 'Assegnazione rimossa.');
688
+    }
689
+
690
+    private function tavoloPayload(EventoTavolo $t): array
691
+    {
692
+        $occupati = $t->postiOccupati();
693
+
694
+        return [
695
+            'id' => $t->id,
696
+            'label' => $t->label,
697
+            'posti' => (int) $t->posti,
698
+            'occupati' => $occupati,
699
+            'liberi' => max(0, (int) $t->posti - $occupati),
700
+            'x' => (float) $t->x,
701
+            'y' => (float) $t->y,
702
+            'w' => (float) $t->w,
703
+            'h' => (float) $t->h,
704
+            'forma' => $t->forma ?: 'rettangolo',
705
+            'gruppo_id' => $t->gruppo_id,
706
+            'assegnazioni' => $t->assegnazioni->map(fn ($a) => [
707
+                'id' => $a->id,
708
+                'posti' => (int) $a->posti_assegnati,
709
+                'prenotazione_id' => (int) $a->prenotazione_id,
710
+                'nome' => trim(($a->prenotazione?->cognome ?? '').' '.($a->prenotazione?->nome ?? '')),
711
+                'codice' => $a->prenotazione?->codice,
712
+            ])->values(),
713
+        ];
714
+    }
715
+
716
+    private function prenotazionePayload(Prenotazione $p): array
717
+    {
718
+        $coperti = max(1, (int) ($p->numero_persone ?? 1));
719
+        $assegnati = (int) $p->assegnazioniTavolo->sum('posti_assegnati');
720
+
721
+        return [
722
+            'id' => $p->id,
723
+            'nome' => trim(($p->cognome ?? '').' '.($p->nome ?? '')),
724
+            'codice' => $p->codice,
725
+            'stato' => $p->stato,
726
+            'confermata' => (bool) $p->confermata,
727
+            'coperti' => $coperti,
728
+            'assegnati' => $assegnati,
729
+            'rimasti' => max(0, $coperti - $assegnati),
730
+            'assegnazioni' => $p->assegnazioniTavolo->map(fn ($a) => [
731
+                'id' => $a->id,
732
+                'posti' => (int) $a->posti_assegnati,
733
+                'tavolo_id' => (int) $a->evento_tavolo_id,
734
+                'label' => $a->eventoTavolo?->label,
735
+                'gruppo_id' => $a->eventoTavolo?->gruppo_id,
736
+            ])->values(),
737
+        ];
738
+    }
739
+
740
+    private function findEventoOrFail(mixed $eventoId): Evento
741
+    {
742
+        $evento = Evento::find($eventoId);
743
+        if (! $evento) {
744
+            abort(404, 'Evento non trovato');
745
+        }
746
+
747
+        AttivitaService::garantisciEventoDiQuestaAttivita($evento);
748
+
749
+        return $evento;
750
+    }
751
+
752
+    /**
753
+     * @return \Illuminate\Support\Collection<int, EventoSala>
754
+     */
755
+    private function saleList(Evento $evento)
756
+    {
757
+        $sale = $evento->sale()->get();
758
+        if ($sale->isEmpty()) {
759
+            $sale = collect([$this->ensureSala($evento)]);
760
+        }
761
+
762
+        return $sale;
763
+    }
764
+
765
+    private function resolveSala(Request $request, Evento $evento, $sale = null): EventoSala
766
+    {
767
+        $sale = $sale ?? $this->saleList($evento);
768
+        $salaId = (int) ($request->input('sala_id') ?: $request->query('sala_id') ?: 0);
769
+
770
+        if ($salaId > 0) {
771
+            $found = $sale->firstWhere('id', $salaId);
772
+            if ($found) {
773
+                return $found;
774
+            }
775
+            abort(404, 'Sala non trovata');
776
+        }
777
+
778
+        return $sale->first() ?? $this->ensureSala($evento);
779
+    }
780
+
781
+    private function ensureSala(Evento $evento): EventoSala
782
+    {
783
+        $sala = $evento->sale()->orderBy('ordine')->orderBy('id')->first();
784
+        if ($sala) {
785
+            return $sala;
786
+        }
787
+
788
+        return EventoSala::create([
789
+            'evento_id' => $evento->id,
790
+            'nome' => 'Sala principale',
791
+            'ordine' => 0,
792
+        ]);
793
+    }
794
+
795
+    private function piantinaParams(Evento $evento, EventoSala $sala): array
796
+    {
797
+        return [
798
+            'evento_id' => $evento->id,
799
+            'sala_id' => $sala->id,
800
+        ];
801
+    }
802
+
803
+    private function piantinaUrl(?EventoSala $sala): ?string
804
+    {
805
+        if (! $sala || ! filled($sala->immagine)) {
806
+            return null;
807
+        }
808
+
809
+        $disk = Storage::disk('eventi');
810
+        if (! $disk->exists($sala->immagine)) {
811
+            return null;
812
+        }
813
+
814
+        return $disk->url($sala->immagine).'?v='.$disk->lastModified($sala->immagine);
815
+    }
816
+
817
+    private function assegnazioneFail(Request $request, Evento $evento, string $message, ?EventoSala $sala = null)
818
+    {
819
+        if ($request->expectsJson() || $request->wantsJson()) {
820
+            return response()->json(['ok' => false, 'error' => $message], 422);
821
+        }
822
+
823
+        $params = ['evento_id' => $evento->id];
824
+        if ($sala) {
825
+            $params['sala_id'] = $sala->id;
826
+        } elseif ($request->input('sala_id') || $request->query('sala_id')) {
827
+            $params['sala_id'] = (int) ($request->input('sala_id') ?: $request->query('sala_id'));
828
+        }
829
+
830
+        return redirect()
831
+            ->route('evento.piantina.assegnazioni', $params)
832
+            ->with('error', $message);
833
+    }
834
+}

+ 10
- 2
app/Http/Controllers/FatturaController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Fattura;
7 9
 use App\DataTables\FatturaDataTable;
@@ -22,8 +24,8 @@ public static $permissions = [
22 24
 public static function middleware(): array
23 25
 {
24 26
     return [
25
-        new Middleware('permission:view-fattura', only: ['index', 'show']),
26
-        new Middleware('permission:create-fattura|edit-fattura|delete-fattura', only: ['store', 'update', 'destroy']),
27
+            new Middleware('permission:view-fattura', only: ['index', 'show', 'need_fatturazione_mensile']),
28
+            new Middleware('permission:create-fattura|edit-fattura|delete-fattura', only: ['store', 'update', 'destroy', 'registra_pagamento']),
27 29
     ];
28 30
 }
29 31
 
@@ -62,6 +64,9 @@ public function show(Request $request)
62 64
     if(!Auth::user()->hasAnyRole(['superadmin','amministratore'])) return response()->json(['error' => 'Non hai i permessi per vedere una fattura'],403);
63 65
 
64 66
     $fattura = Fattura::findOrFail($request->fattura_id);
67
+    if (! Auth::user()->hasRole('superadmin') && (int) $fattura->user_id !== (int) Auth::id()) {
68
+        abort(404);
69
+    }
65 70
     return view('fattura.show', compact('fattura'));
66 71
 }
67 72
 
@@ -74,6 +79,9 @@ public function need_fatturazione_mensile()
74 79
 public function registra_pagamento(Request $request)
75 80
 {
76 81
     $fattura = Fattura::findOrFail($request->fattura_id);
82
+    if (! Auth::user()->hasRole('superadmin') && (int) $fattura->user_id !== (int) Auth::id()) {
83
+        abort(404);
84
+    }
77 85
     $fattura->stato = Fattura::PAGATA;
78 86
     $fattura->info= json_encode(['pagamento_registrato_il' => now()]);
79 87
     $fattura->save();

+ 6
- 1
app/Http/Controllers/FornitoreController.php Просмотреть файл

@@ -2,11 +2,14 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Fornitore;
7 9
 use App\DataTables\FornitoreDataTable;
8 10
 use App\DataTables\FornitoreDataTableEditor;
9 11
 use Illuminate\Support\Facades\Auth;
12
+use App\Services\Attivita\AttivitaService;
10 13
 
11 14
 class FornitoreController extends Controller
12 15
 {
@@ -21,7 +24,7 @@ class FornitoreController extends Controller
21 24
     public static function middleware(): array
22 25
     {
23 26
         return [
24
-            new Middleware('permission:view-fornitore', only: ['index', 'show']),
27
+            new Middleware('permission:view-fornitore', only: ['index', 'show', 'show_modal']),
25 28
             new Middleware('permission:create-fornitore|edit-fornitore|delete-fornitore', only: ['store', 'update', 'destroy']),
26 29
         ];
27 30
     }
@@ -56,6 +59,7 @@ class FornitoreController extends Controller
56 59
     {
57 60
         $fornitore = Fornitore::find($request->get('fornitore_id'));
58 61
         if(!$fornitore) return redirect()->route('fornitore.index')->with('error', 'Fornitore non trovato');
62
+        AttivitaService::garantisciAttivita($fornitore->attivita_id);
59 63
         if(!Auth::user()->can('view-fornitore')) return abort(403, 'Non hai permesso di vedere questo fornitore');
60 64
         return view('fornitore.show_modal', ['fornitore' => $fornitore]);
61 65
     }
@@ -64,6 +68,7 @@ class FornitoreController extends Controller
64 68
     {
65 69
         $fornitore = Fornitore::find($request->get('fornitore_id'));
66 70
         if(!$fornitore) return redirect()->route('fornitore.index')->with('error', 'Fornitore non trovato');
71
+        AttivitaService::garantisciAttivita($fornitore->attivita_id);
67 72
         if(!Auth::user()->can('view-fornitore')) return abort(403, 'Non hai permesso di vedere questo fornitore');
68 73
         return view('fornitore.show', ['fornitore' => $fornitore]);
69 74
     }

+ 5
- 1
app/Http/Controllers/ImpostazioniController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use App\Models\Attivita;
6 8
 use Illuminate\Http\Request;
7 9
 use App\Models\Impostazioni;
@@ -9,6 +11,7 @@ use Illuminate\Support\Facades\Auth;
9 11
 use Illuminate\Support\Facades\Session;
10 12
 use App\DataTables\ImpostazioniDataTable;
11 13
 use App\DataTables\ImpostazioniDataTableEditor;
14
+use App\Services\Attivita\AttivitaService;
12 15
 
13 16
 class ImpostazioniController extends Controller
14 17
 {
@@ -24,7 +27,7 @@ class ImpostazioniController extends Controller
24 27
     {
25 28
         return [
26 29
             new Middleware('permission:view-impostazioni', only: ['index']),
27
-            new Middleware('permission:create-impostazioni|edit-impostazioni|delete-impostazioni', only: ['store']),
30
+            new Middleware('permission:create-impostazioni|edit-impostazioni|delete-impostazioni', only: ['store', 'edit']),
28 31
         ];
29 32
     }
30 33
     
@@ -69,6 +72,7 @@ class ImpostazioniController extends Controller
69 72
     {
70 73
         $impostazione = Impostazioni::find($impostazione_id);
71 74
         if(!$impostazione) return redirect()->route('impostazioni.index')->with('error', 'Impostazione non trovata');
75
+        AttivitaService::garantisciAttivita($impostazione->attivita_id);
72 76
         return view('impostazioni.edit', compact('impostazione'));
73 77
     }
74 78
 }

+ 5
- 4
app/Http/Controllers/ListinoPrezziController.php Просмотреть файл

@@ -3,6 +3,7 @@
3 3
 namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6
+use Illuminate\Routing\Controllers\Middleware;
6 7
 use App\Models\ListinoPrezzi;
7 8
 use Illuminate\Support\Facades\Auth;
8 9
 use Illuminate\Support\Facades\Validator;
@@ -22,10 +23,10 @@ class ListinoPrezziController extends Controller
22 23
     
23 24
     public static function middleware(): array
24 25
     {
25
-        return  [
26
-                    new Middleware('role:superadmin', ['only' => ['index', 'store']]),
27
-                    new Middleware('role:amministratore', ['only' => ['show_listino_cliente']]),
28
-                ];
26
+        return [
27
+            new Middleware('role:superadmin', only: ['index', 'store']),
28
+            new Middleware('role:amministratore', only: ['show_listino_cliente']),
29
+        ];
29 30
     }
30 31
 
31 32
     public function index(ListinoPrezziDataTable $dataTable)

+ 13
- 4
app/Http/Controllers/MappaDispositiviController.php Просмотреть файл

@@ -14,6 +14,7 @@ use App\DataTables\DispositivoDataTableEditor;
14 14
 use Illuminate\Support\Facades\Auth;
15 15
 use Illuminate\Support\Facades\Session;
16 16
 use Illuminate\Routing\Controllers\Middleware;
17
+use App\Services\Attivita\AttivitaService;
17 18
 
18 19
 class MappaDispositiviController extends Controller
19 20
 {
@@ -28,13 +29,14 @@ class MappaDispositiviController extends Controller
28 29
     public static function middleware(): array
29 30
     {
30 31
         return [
31
-            new Middleware('permission:view-mappa_dispositivi', only: ['index']),
32
+            new Middleware('permission:view-mappa_dispositivi', only: ['index', 'show']),
32 33
             new Middleware('permission:create-mappa_dispositivi|edit-mappa_dispositivi|delete-mappa_dispositivi', only: ['store', 'update', 'destroy']),
33 34
         ];
34 35
     }
35 36
     
36 37
     public function index(DispositivoDataTable $dataTable)
37 38
     {
39
+        $dataTable->attivita_id = Session::get('attivita_attuale');
38 40
         if (request()->ajax()) {
39 41
             return $dataTable->ajax();
40 42
         }
@@ -93,6 +95,11 @@ class MappaDispositiviController extends Controller
93 95
     public function show($dispositivo_id)
94 96
     {
95 97
         $dispositivo = Dispositivo::find($dispositivo_id);
98
+        if (! $dispositivo) {
99
+            abort(404);
100
+        }
101
+        AttivitaService::garantisciAttivita($dispositivo->attivita_id);
102
+
96 103
         return view('mappa_dispositivi.show', ['dispositivo' => $dispositivo]);
97 104
     }
98 105
 
@@ -105,9 +112,11 @@ class MappaDispositiviController extends Controller
105 112
         $grouped = array_fill_keys($tipi, []);
106 113
         $grouped['_altro'] = [];
107 114
 
108
-        $attivitaAttiveIds = Attivita::query()
109
-            ->where('is_attiva', true)
110
-            ->pluck('id');
115
+        $attivitaQuery = Attivita::query()->where('is_attiva', true);
116
+        if (! Auth::user()?->hasRole('superadmin')) {
117
+            $attivitaQuery->where('user_id', Auth::id());
118
+        }
119
+        $attivitaAttiveIds = $attivitaQuery->pluck('id');
111 120
 
112 121
         $devices = Dispositivo::query()
113 122
             ->with('attivita:id,nome')

+ 3
- 1
app/Http/Controllers/MetodoPagamentoController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\MetodoPagamento;
7 9
 use App\DataTables\MetodoPagamentoDataTable;
@@ -23,7 +25,7 @@ class MetodoPagamentoController extends Controller
23 25
     {
24 26
         return [
25 27
             new Middleware('permission:view-metodo_pagamento', only: ['index']),
26
-            new Middleware('permission:create-metodo_pagamento|edit-metodo_pagamento|delete-metodo_pagamento', only: ['store', 'update', 'destroy']),
28
+            new Middleware('permission:create-metodo_pagamento|edit-metodo_pagamento|delete-metodo_pagamento', only: ['store', 'update', 'destroy', 'segresta_wallet_chiE']),
27 29
         ];
28 30
     }
29 31
     

+ 25
- 2
app/Http/Controllers/MonitorController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Dispositivo;
7 9
 use App\Models\MonitorHasContenuto;
@@ -11,6 +13,7 @@ use App\DataTables\MonitorDataTableEditor;
11 13
 use Illuminate\Support\Facades\Auth;
12 14
 use Carbon\Carbon;
13 15
 use Illuminate\Support\Facades\Session;
16
+use App\Services\Attivita\AttivitaService;
14 17
 
15 18
 
16 19
 class MonitorController extends Controller
@@ -26,8 +29,8 @@ class MonitorController extends Controller
26 29
     public static function middleware(): array
27 30
     {
28 31
         return [
29
-            new Middleware('permission:view-monitor', only: ['index']),
30
-            new Middleware('permission:create-monitor|edit-monitor|delete-monitor', only: ['store', 'update', 'destroy']),
32
+            new Middleware('permission:view-monitor', only: ['index', 'show']),
33
+            new Middleware('permission:create-monitor|edit-monitor|delete-monitor', only: ['store', 'update', 'destroy', 'gestisci_contenuto_monitor', 'gestisci_contenuto_store']),
31 34
         ];
32 35
     }
33 36
     
@@ -61,6 +64,7 @@ class MonitorController extends Controller
61 64
         if($monitor == null){
62 65
             return redirect()->route('monitor.index')->with('error', 'Dispositivo monitor non trovato');
63 66
         }
67
+        AttivitaService::garantisciAttivita($monitor->attivita_id);
64 68
 
65 69
         $monitor_has_contenuto = MonitorHasContenuto::with(['cucina', 'contenuto_bacheca', 'bacheca.contenuti'])
66 70
             ->where('monitor_id', $monitor->id)
@@ -102,6 +106,7 @@ class MonitorController extends Controller
102 106
         if($monitor == null){
103 107
             abort(404, 'Dispositivo monitor non trovato');
104 108
         }
109
+        AttivitaService::garantisciAttivita($monitor->attivita_id);
105 110
         $monitor_has_contenuto = MonitorHasContenuto::where('monitor_id', $monitor->id)->first();
106 111
 
107 112
         $bacheche = Bacheca::query()
@@ -146,6 +151,24 @@ class MonitorController extends Controller
146 151
 
147 152
         $isBacheca = (bool) $request->boolean('is_bacheca');
148 153
 
154
+        $monitor = Dispositivo::find($request->get('monitor_id'));
155
+        if (! $monitor) {
156
+            abort(404);
157
+        }
158
+        AttivitaService::garantisciAttivita($monitor->attivita_id);
159
+
160
+        if ($isBacheca) {
161
+            $bacheca = Bacheca::find($request->get('bacheca_id'));
162
+            if (! $bacheca || (int) $bacheca->attivita_id !== (int) $monitor->attivita_id) {
163
+                abort(404);
164
+            }
165
+        } else {
166
+            $cucina = \App\Models\Cucina::find($request->get('cucina_id'));
167
+            if (! $cucina || (int) $cucina->attivita_id !== (int) $monitor->attivita_id) {
168
+                abort(404);
169
+            }
170
+        }
171
+
149 172
         MonitorHasContenuto::updateOrCreate([
150 173
             'monitor_id' => $request->get('monitor_id'),
151 174
         ], [

+ 26
- 3
app/Http/Controllers/OperatoreController.php Просмотреть файл

@@ -8,7 +8,6 @@ use App\DataTables\OperatoreDataTable;
8 8
 use App\DataTables\OperatoreDataTableEditor;
9 9
 use Illuminate\Support\Facades\Auth;
10 10
 use Illuminate\Routing\Controllers\Middleware;
11
-use Illuminate\Routing\Controllers\HasMiddleware;
12 11
 use Illuminate\Support\Facades\Hash;
13 12
 use Illuminate\Support\Facades\Validator;
14 13
 use Illuminate\Support\Str;
@@ -17,6 +16,7 @@ use App\Models\Dispositivo;
17 16
 use App\Models\Ordine;
18 17
 use Illuminate\Support\Facades\Session;
19 18
 use App\DataTables\RigaOrdineDataTable;
19
+use App\Services\Attivita\AttivitaService;
20 20
 
21 21
 
22 22
 class OperatoreController extends Controller
@@ -32,8 +32,8 @@ class OperatoreController extends Controller
32 32
     public static function middleware(): array
33 33
     {
34 34
         return [
35
-            new Middleware('permission:view-operatore', only: ['index']),
36
-            new Middleware('permission:create-operatore|edit-operatore|delete-operatore', only: ['store', 'update', 'destroy']),
35
+            new Middleware('permission:view-operatore', only: ['index', 'show']),
36
+            new Middleware('permission:create-operatore|edit-operatore|delete-operatore', only: ['store', 'update', 'destroy', 'update_password', 'update_dispositivi']),
37 37
         ];
38 38
     }
39 39
     
@@ -50,12 +50,17 @@ class OperatoreController extends Controller
50 50
         if (!$operatore) {
51 51
             return redirect()->back()->with('error', 'Operatore non trovato');
52 52
         }
53
+        AttivitaService::garantisciAttivita($operatore->attivita_id);
53 54
         return view('operatore.show', ['operatore' => $operatore , 'dispositivi' => $operatore->dispositivi]);
54 55
     }
55 56
 
56 57
     public function update_password(Request $request)
57 58
     {
58 59
         $operatore = Operatore::find($request->get('operatore_id'));
60
+        if (!$operatore) {
61
+            return redirect()->back()->with('error', 'Operatore non trovato');
62
+        }
63
+        AttivitaService::garantisciAttivita($operatore->attivita_id);
59 64
         $operatore->password = Hash::make($request->get('password'));
60 65
         $operatore->save();
61 66
         return redirect()->route('operatore.show', ['operatore_id' => $operatore->id])->with('success', 'Password aggiornata con successo');
@@ -78,6 +83,17 @@ class OperatoreController extends Controller
78 83
         if (!$operatore) {
79 84
             return redirect()->back()->with('error', 'Operatore non trovato');
80 85
         }
86
+        AttivitaService::garantisciAttivita($operatore->attivita_id);
87
+
88
+        $ids = array_values(array_unique(array_map('intval', $ids)));
89
+        if ($ids !== []) {
90
+            $dispositivi = Dispositivo::query()->whereIn('id', $ids)->get();
91
+            if ($dispositivi->count() !== count($ids)
92
+                || $dispositivi->contains(fn ($dispositivo) => (int) $dispositivo->attivita_id !== (int) $operatore->attivita_id)
93
+            ) {
94
+                abort(404);
95
+            }
96
+        }
81 97
 
82 98
         $operatore->dispositivi()->sync($ids);
83 99
 
@@ -174,6 +190,13 @@ class OperatoreController extends Controller
174 190
             return redirect()->route('punto-vendita.index')
175 191
             ->with('error', 'Punto di vendita non trovato');
176 192
         }
193
+        $operatore = Auth::guard('operatore')->user();
194
+        if (! $operatore
195
+            || (int) $puntoVendita->attivita_id !== (int) $operatore->attivita_id
196
+            || ! $operatore->dispositivi()->where('dispositivo.id', $puntoVendita->id)->exists()
197
+        ) {
198
+            return redirect()->route('operatore.landing')->with('error', 'Non sei autorizzato a accedere a questo dispositivo');
199
+        }
177 200
 // dd('A',$puntoVendita);
178 201
         if($puntoVendita->binding_token == '' || $puntoVendita->binding_token == null ){
179 202
             $puntoVendita->binding_token = Hash::make(Str::random(32));

+ 24
- 2
app/Http/Controllers/OrdineController.php Просмотреть файл

@@ -2,11 +2,14 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Ordine;
7 9
 use App\DataTables\OrdineDataTable;
8 10
 use App\DataTables\OrdineDataTableEditor;
9 11
 use Illuminate\Support\Facades\Auth;
12
+use App\Services\Attivita\AttivitaService;
10 13
 
11 14
 class OrdineController extends Controller
12 15
 {
@@ -21,7 +24,7 @@ class OrdineController extends Controller
21 24
     public static function middleware(): array
22 25
     {
23 26
         return [
24
-            new Middleware('permission:view-ordine', only: ['index']),
27
+            new Middleware('permission:view-ordine', only: ['index', 'show', 'show_modal']),
25 28
             new Middleware('permission:create-ordine|edit-ordine|delete-ordine', only: ['store', 'update', 'destroy']),
26 29
         ];
27 30
     }
@@ -53,13 +56,32 @@ class OrdineController extends Controller
53 56
 
54 57
     public function show(Request $request)
55 58
     {
56
-        $ordine = Ordine::find($request->get('ordine_id'));
59
+        $ordine = Ordine::with([
60
+            'dispositivo',
61
+            'attivita',
62
+            'prenotazione',
63
+            'pagamenti.metodo_pagamento',
64
+            'asporto',
65
+            'righe_ordine.piatto.cucina',
66
+            'righe_ordine.piatto.elencoAllergeni',
67
+            'righe_ordine.has_variante.variante_piatto',
68
+        ])->find($request->get('ordine_id'));
69
+        if (! $ordine) {
70
+            abort(404);
71
+        }
72
+        AttivitaService::garantisciAttivita($ordine->attivita_id);
73
+
57 74
         return view('ordine.show', compact('ordine'));
58 75
     }
59 76
 
60 77
     public function show_modal(Request $request)
61 78
     {
62 79
         $ordine = Ordine::find($request->get('ordine_id'));
80
+        if (! $ordine) {
81
+            abort(404);
82
+        }
83
+        AttivitaService::garantisciAttivita($ordine->attivita_id);
84
+
63 85
         return view('ordine.show_modal', compact('ordine'));
64 86
     }
65 87
 }

+ 107
- 14
app/Http/Controllers/PagamentoController.php Просмотреть файл

@@ -2,12 +2,15 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Pagamento;
7
-use App\Models\MetodoPagamento;
9
+use App\Models\PrimaNota;
8 10
 use App\DataTables\PagamentoDataTable;
9 11
 use App\DataTables\PagamentoDataTableEditor;
10 12
 use Illuminate\Support\Facades\Auth;
13
+use App\Services\Attivita\AttivitaService;
11 14
 
12 15
 class PagamentoController extends Controller
13 16
 {
@@ -17,13 +20,15 @@ class PagamentoController extends Controller
17 20
         'create-pagamento' => 'Crea',
18 21
         'edit-pagamento' => 'Modifica',
19 22
         'delete-pagamento' => 'Elimina',
23
+        'storna-pagamento' => 'Storna',
20 24
     ];
21 25
 
22 26
     public static function middleware(): array
23 27
     {
24 28
         return [
25
-            new Middleware('permission:view-pagamento', only: ['index', 'show']),
29
+            new Middleware('permission:view-pagamento', only: ['index', 'show', 'show_modal']),
26 30
             new Middleware('permission:create-pagamento|edit-pagamento|delete-pagamento', only: ['store', 'update', 'destroy']),
31
+            new Middleware('permission:storna-pagamento|edit-pagamento', only: ['stornaPagamento']),
27 32
         ];
28 33
     }
29 34
 
@@ -37,29 +42,117 @@ class PagamentoController extends Controller
37 42
     {
38 43
         $request = request();
39 44
         $input = $request->all();
40
-        if($request->has('action')){
41
-            switch($input['action']){
45
+        if ($request->has('action')) {
46
+            switch ($input['action']) {
42 47
                 case 'create':
43
-                    if(!Auth::user()->can('create-pagamento')) return;
48
+                    if (! Auth::user()->can('create-pagamento')) {
49
+                        return;
50
+                    }
44 51
                     break;
45 52
                 case 'edit':
46
-                    if(!Auth::user()->can('edit-pagamento')) return;
53
+                    if (! Auth::user()->can('edit-pagamento')) {
54
+                        return;
55
+                    }
47 56
                     break;
48 57
                 case 'remove':
49
-                    if(!Auth::user()->can('delete-pagamento')) return;
58
+                    if (! Auth::user()->can('delete-pagamento')) {
59
+                        return;
60
+                    }
50 61
                     break;
51
-                }
62
+            }
63
+        }
64
+
52 65
         return $editor->process($request);
53 66
     }
54
-}
67
+
68
+    public function show_modal(Request $request)
69
+    {
70
+        $pagamento = Pagamento::query()->find($request->get('pagamento_id'));
71
+        if (! $pagamento) {
72
+            return redirect()->route('pagamento.index')->with('error', 'Pagamento non trovato');
73
+        }
74
+
75
+        AttivitaService::garantisciAttivita($pagamento->attivita_id);
76
+
77
+        if (! Auth::user()->can('view-pagamento')) {
78
+            return abort(403, 'Non hai permesso di vedere questo pagamento');
79
+        }
80
+
81
+        $pagamento->loadMissing(['metodo_pagamento', 'ordine', 'prenotazione', 'attivita', 'movimenti_prima_nota.categoria_contabile']);
82
+
83
+        return view('pagamento.show_modal', compact('pagamento'));
84
+    }
55 85
 
56 86
     public function show(Request $request)
57 87
     {
58
-        $pagamento = Pagamento::find($request->get('pagamento_id'));
59
-        if(!$pagamento) return redirect()->route('pagamento.index')->with('error', 'Pagamento non trovato');
88
+        $pagamento = Pagamento::query()->find($request->get('pagamento_id'));
89
+        if (! $pagamento) {
90
+            return redirect()->route('pagamento.index')->with('error', 'Pagamento non trovato');
91
+        }
92
+
93
+        AttivitaService::garantisciAttivita($pagamento->attivita_id);
94
+
95
+        if (! Auth::user()->can('view-pagamento')) {
96
+            return abort(403, 'Non hai permesso di vedere questo pagamento');
97
+        }
98
+
99
+        $pagamento->loadMissing(['metodo_pagamento', 'ordine', 'prenotazione', 'attivita', 'movimenti_prima_nota.categoria_contabile']);
100
+
101
+        return view('pagamento.show', compact('pagamento'));
102
+    }
103
+
104
+    public function stornaPagamento(Request $request)
105
+    {
106
+        $pagamento = Pagamento::query()->find($request->get('pagamento_id'));
107
+        if (! $pagamento) {
108
+            return response()->json(['success' => false, 'message' => 'Pagamento non trovato'], 404);
109
+        }
110
+
111
+        AttivitaService::garantisciAttivita($pagamento->attivita_id);
112
+
113
+        $info = $pagamento->info ?? [];
114
+        if (($info['storno'] ?? false) || $pagamento->stato === Pagamento::ANNULLATO) {
115
+            return response()->json(['success' => false, 'message' => 'Pagamento già stornato'], 422);
116
+        }
117
+
118
+        if ($pagamento->movimenti_prima_nota()->where('tipo_movimento', PrimaNota::USCITA)->exists()) {
119
+            return response()->json(['success' => false, 'message' => 'Pagamento già stornato'], 422);
120
+        }
121
+
122
+        $movimento = $pagamento->movimenti_prima_nota()
123
+            ->whereIn('tipo_movimento', [PrimaNota::ENTRATA, PrimaNota::NO_CONTABILE])
124
+            ->first();
125
+
126
+        if (! $movimento) {
127
+            return response()->json(['success' => false, 'message' => 'Movimento originale non trovato'], 422);
128
+        }
129
+
130
+        $tipoStorno = $movimento->tipo_movimento === PrimaNota::NO_CONTABILE
131
+            ? PrimaNota::NO_CONTABILE
132
+            : PrimaNota::USCITA;
133
+
134
+        PrimaNota::create([
135
+            'attivita_id' => $pagamento->attivita_id,
136
+            'categoria_contabile_id' => $movimento->categoria_contabile_id,
137
+            'pagamento_id' => $pagamento->id,
138
+            'fornitore_id' => $movimento->fornitore_id,
139
+            'ordine_id' => $pagamento->ordine_id,
140
+            'prenotazione_id' => $pagamento->prenotazione_id,
141
+            'evento_id' => $movimento->evento_id,
142
+            'tipo_movimento' => $tipoStorno,
143
+            'importo' => $pagamento->importo,
144
+            'causale' => 'Storno pagamento #' . $pagamento->id . ' - ' . $pagamento->causale,
145
+            'riferimento' => 'storno:pagamento:' . $pagamento->id,
146
+        ]);
147
+
148
+        $pagamento->stato = Pagamento::ANNULLATO;
149
+        $pagamento->info = array_merge($info, [
150
+            'storno' => true,
151
+            'storno_data' => now()->toIso8601String(),
152
+            'storno_user' => Auth::id(),
153
+        ]);
154
+        $pagamento->save();
60 155
 
61
-        if(!Auth::user()->can('view-pagamento')) return abort(403, 'Non hai permesso di vedere questo pagamento');
62
-        // if($request->has('modal')){
63
-        return view('pagamento.show', ['pagamento' => $pagamento]);
156
+        return response()->json(['success' => true]);
64 157
     }
65 158
 }

+ 10
- 1
app/Http/Controllers/PiattoController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Piatto;
7 9
 use App\Models\PiattoHasAllergene;
@@ -9,6 +11,7 @@ use App\DataTables\PiattoDataTable;
9 11
 use App\DataTables\PiattoDataTableEditor;
10 12
 use Illuminate\Support\Facades\Auth;
11 13
 use Illuminate\Support\Facades\Session;
14
+use App\Services\Attivita\AttivitaService;
12 15
 
13 16
 class PiattoController extends Controller
14 17
 {
@@ -23,7 +26,7 @@ class PiattoController extends Controller
23 26
     public static function middleware(): array
24 27
     {
25 28
         return [
26
-            new Middleware('permission:view-piatto', only: ['index']),
29
+            new Middleware('permission:view-piatto', only: ['index', 'datatable']),
27 30
             new Middleware('permission:create-piatto|edit-piatto|delete-piatto', only: ['store', 'update', 'destroy']),
28 31
         ];
29 32
     }
@@ -100,6 +103,12 @@ class PiattoController extends Controller
100 103
 
101 104
       foreach ($payload as $piattoId => $data) {
102 105
         $piattoId = (int) $piattoId;
106
+        $piatto = Piatto::find($piattoId);
107
+        if (! $piatto) {
108
+          abort(404);
109
+        }
110
+        AttivitaService::garantisciAttivita($piatto->attivita_id);
111
+
103 112
         $allergenIds = $data['allergeni'] ?? [];
104 113
 
105 114
         if (is_string($allergenIds)) {

+ 1326
- 49
app/Http/Controllers/PrenotazioneController.php
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 15
- 3
app/Http/Controllers/PrenotazioneTavoloController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\PrenotazioneTavolo;
7 9
 use App\DataTables\PrenotazioneTavoloDataTable;
@@ -11,6 +13,7 @@ use App\Models\Attivita;
11 13
 use Illuminate\Support\Facades\Validator;
12 14
 use Illuminate\Support\Str;
13 15
 use Illuminate\Support\Facades\Session;
16
+use App\Models\Tavolo;
14 17
 
15 18
 class PrenotazioneTavoloController extends Controller
16 19
 {
@@ -26,7 +29,7 @@ class PrenotazioneTavoloController extends Controller
26 29
     public static function middleware(): array
27 30
     {
28 31
         return [
29
-            new Middleware('permission:view-prenotazione_tavolo', only: ['index']),
32
+            new Middleware('permission:view-prenotazione_tavolo', only: ['index', 'oggi', 'appelloPrenotazioniTavoli']),
30 33
             new Middleware('permission:create-prenotazione_tavolo|edit-prenotazione_tavolo|delete-prenotazione_tavolo', only: ['store', 'update', 'destroy']),
31 34
         ];
32 35
     }
@@ -102,8 +105,16 @@ class PrenotazioneTavoloController extends Controller
102 105
             'data_prenotazione' => 'required|date',
103 106
             'ora_prenotazione' => 'required',
104 107
         ]);
108
+        $tavolo = Tavolo::find($request->tavolo_id);
109
+        if (! $tavolo || (int) $tavolo->attivita_id !== (int) $attivita->id) {
110
+            return redirect()->back()->with('error', 'Tavolo non valido');
111
+        }
105 112
         $prenotazione = new PrenotazioneTavolo();
106
-        $prenotazione->fill($request->all());
113
+        $prenotazione->fill($request->only([
114
+            'nome', 'email', 'telefono', 'data_prenotazione', 'ora_prenotazione',
115
+        ]));
116
+        $prenotazione->attivita_id = $attivita->id;
117
+        $prenotazione->tavolo_id = $tavolo->id;
107 118
         $prenotazione->stato = PrenotazioneTavolo::STATO_INVIATA;
108 119
         // dd($prenotazione);
109 120
         $prenotazione->save();
@@ -112,7 +123,8 @@ class PrenotazioneTavoloController extends Controller
112 123
     }
113 124
 
114 125
     public function cliente_show(Request $request, $prenotazione_tavoli_id){
115
-        $prenotazione = PrenotazioneTavolo::find($request->get('prenotazione_tavolo_id')|| $prenotazione_tavoli_id);
126
+        $id = $prenotazione_tavoli_id ?: $request->get('prenotazione_tavolo_id');
127
+        $prenotazione = PrenotazioneTavolo::find($id);
116 128
         if(!$prenotazione) return redirect()->route('cliente.attivita.show')->with('error', 'Prenotazione non trovata');
117 129
         return view('prenotazione_tavolo.cliente.show')->with(['prenotazione' => $prenotazione]);
118 130
     }

+ 22
- 3
app/Http/Controllers/PrimaNotaController.php Просмотреть файл

@@ -9,6 +9,7 @@ use App\DataTables\PrimaNotaDataTable;
9 9
 use App\DataTables\PrimaNotaDataTableEditor;
10 10
 use Illuminate\Support\Facades\Auth;
11 11
 use Illuminate\Routing\Controllers\Middleware;
12
+use App\Services\Attivita\AttivitaService;
12 13
 
13 14
 class PrimaNotaController extends Controller
14 15
 { 
@@ -23,7 +24,7 @@ class PrimaNotaController extends Controller
23 24
     public static function middleware(): array
24 25
     {
25 26
         return [
26
-            new Middleware('permission:view-primanota', only: ['index', 'statistiche']),
27
+            new Middleware('permission:view-primanota', only: ['index', 'statistiche', 'show']),
27 28
             new Middleware('permission:create-primanota|edit-primanota|delete-primanota', only: ['store', 'update', 'destroy']),
28 29
         ];
29 30
     }
@@ -88,12 +89,30 @@ class PrimaNotaController extends Controller
88 89
                     break;
89 90
                 }
90 91
         return $editor->process($request);
92
+        }
91 93
     }
92
-}
94
+
93 95
 
94 96
     public function show(Request $request)
95 97
     {
96
-        $primanota = PrimaNota::find($request->get('primanota_id'));
98
+        $primanota = PrimaNota::query()->find($request->get('primanota_id'));
99
+        if (! $primanota) {
100
+            return redirect()->route('prima-nota.index')->with('error', 'Prima nota non trovata');
101
+        }
102
+        AttivitaService::garantisciAttivita($primanota->attivita_id);
103
+
104
+        $primanota->loadMissing([
105
+            'attivita',
106
+            'categoria_contabile',
107
+            'pagamento.metodo_pagamento',
108
+            'ordine',
109
+            'prenotazione',
110
+            'evento',
111
+            'fornitore',
112
+        ]);
113
+
97 114
         return view('prima_nota.show', compact('primanota'));
98 115
     }
116
+
117
+
99 118
 }

+ 12
- 2
app/Http/Controllers/PrintJobController.php Просмотреть файл

@@ -2,11 +2,14 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\PrintJob;
7 9
 use App\DataTables\PrintJobDataTable;
8 10
 use App\DataTables\PrintJobDataTableEditor;
9 11
 use Illuminate\Support\Facades\Auth;
12
+use App\Services\Attivita\AttivitaService;
10 13
 
11 14
 class PrintJobController extends Controller
12 15
 {
@@ -21,13 +24,14 @@ class PrintJobController extends Controller
21 24
     public static function middleware(): array
22 25
     {
23 26
         return [
24
-            new Middleware('permission:view-print-job', only: ['index']),
27
+            new Middleware('permission:view-print-job', only: ['index', 'show']),
25 28
             new Middleware('permission:create-print-job|edit-print-job|delete-print-job', only: ['store', 'update', 'destroy']),
26 29
         ];
27 30
     }
28 31
     
29 32
     public function index(PrintJobDataTable $dataTable)
30 33
     {
34
+        $dataTable->attivita_id = session('attivita_attuale');
31 35
         return $dataTable->render('print_job.index');
32 36
     }
33 37
     public function store(PrintJobDataTableEditor $editor)
@@ -51,7 +55,13 @@ class PrintJobController extends Controller
51 55
     }
52 56
     public function show(Request $request)
53 57
     {
54
-        $print_job = PrintJob::find($request->get('print_job_id'));
58
+        $print_job = PrintJob::with(['dispositivo', 'stampante'])->find($request->get('print_job_id'));
59
+        if (! $print_job) {
60
+            abort(404);
61
+        }
62
+        AttivitaService::garantisciAttivita(
63
+            $print_job->dispositivo?->attivita_id ?? $print_job->stampante?->attivita_id
64
+        );
55 65
         return view('print_job.show', compact('print_job'));
56 66
     }
57 67
 }

+ 6
- 1
app/Http/Controllers/PuntoOperatoreController.php Просмотреть файл

@@ -2,11 +2,14 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Dispositivo;
7 9
 use App\DataTables\PuntoOperatoreDataTable;
8 10
 use App\DataTables\PuntoOperatoreDataTableEditor;
9 11
 use Illuminate\Support\Facades\Auth;
12
+use App\Services\Attivita\AttivitaService;
10 13
 
11 14
 class PuntoOperatoreController extends Controller
12 15
 {
@@ -22,7 +25,7 @@ class PuntoOperatoreController extends Controller
22 25
     public static function middleware(): array
23 26
     {
24 27
         return [
25
-            new Middleware('permission:view-punto_operatore', only: ['index']),
28
+            new Middleware('permission:view-punto_operatore', only: ['index', 'show']),
26 29
             new Middleware('permission:edit-punto_operatore', only: ['toggle_is_attivo']),
27 30
             new Middleware('permission:create-punto_operatore|edit-punto_operatore|delete-punto_operatore', only: ['store', 'update', 'destroy']),
28 31
         ];
@@ -67,6 +70,7 @@ class PuntoOperatoreController extends Controller
67 70
         if(!$dispositivo){
68 71
             return redirect()->back()->with('error', 'Punto operatore non trovato');
69 72
         }
73
+        AttivitaService::garantisciAttivita($dispositivo->attivita_id);
70 74
 
71 75
         $dispositivo->is_attivo = !$dispositivo->is_attivo;
72 76
         $dispositivo->save();
@@ -79,6 +83,7 @@ class PuntoOperatoreController extends Controller
79 83
         if(!$dispositivo){
80 84
             return redirect()->back()->with('error', 'Punto operatore non trovato');
81 85
         }
86
+        AttivitaService::garantisciAttivita($dispositivo->attivita_id);
82 87
         return view('punto_operatore.show', ['dispositivo' => $dispositivo]);
83 88
     }
84 89
 }

+ 85
- 38
app/Http/Controllers/PuntoVenditaController.php Просмотреть файл

@@ -2,11 +2,14 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use App\DataTables\PuntoVenditaDataTable;
6 8
 use App\DataTables\PuntoVenditaDataTableEditor;
7 9
 use App\DataTables\RigaOrdineDataTable;
8 10
 
9 11
 use App\Models\Dispositivo;
12
+use App\Models\Cucina;
10 13
 use App\Models\Ordine;
11 14
 use App\Models\Pagamento;
12 15
 use App\Models\RigaOrdine;
@@ -14,6 +17,7 @@ use App\Models\RigaOrdineHasVariante;
14 17
 use App\Models\SaltacodaOrdine;
15 18
 use App\Models\SaltacodaRigaOrdine;
16 19
 use App\Models\SaltacodaRigaOrdineHasVariante;
20
+use App\Services\Attivita\AttivitaService;
17 21
 
18 22
 use Illuminate\Support\Str;
19 23
 use Illuminate\Http\Request;
@@ -37,8 +41,14 @@ class PuntoVenditaController extends Controller
37 41
     public static function middleware(): array
38 42
     {
39 43
         return [
40
-            new Middleware('permission:view-punto_vendita', only: ['index', 'dettagli_punto_vendita', 'dettagli']),
41
-            new Middleware('permission:create-punto_vendita|edit-punto_vendita|delete-punto_vendita', only: ['store', 'update', 'destroy', 'edit', 'associa_cucina']),
44
+            new Middleware('permission:view-punto_vendita', only: [
45
+                'index', 'dettagli_punto_vendita', 'dettagli', 'show',
46
+                'riepilogo', 'riepilogo_cassa', 'cerca_pre_ordine',
47
+            ]),
48
+            new Middleware('permission:create-punto_vendita|edit-punto_vendita|delete-punto_vendita', only: [
49
+                'store', 'update', 'destroy', 'edit', 'associa_cucina',
50
+                'dissocia_dispositivo', 'importa_pre_ordine',
51
+            ]),
42 52
         ];
43 53
     }
44 54
 
@@ -58,6 +68,7 @@ class PuntoVenditaController extends Controller
58 68
             return redirect()->route('punto-vendita.index')
59 69
                 ->with('error', 'Punto di vendita non trovato');
60 70
         }
71
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
61 72
 
62 73
         return view('punto_vendita.dettaglio_punto_vendita', compact('puntoVendita'));
63 74
     }
@@ -70,6 +81,7 @@ class PuntoVenditaController extends Controller
70 81
             return redirect()->route('punto-vendita.index')
71 82
                 ->with('error', 'Punto di vendita non trovato');
72 83
         }
84
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
73 85
 
74 86
         return view('punto_vendita.edit', ['puntoVendita' => $puntoVendita]);
75 87
     }
@@ -82,6 +94,7 @@ class PuntoVenditaController extends Controller
82 94
             return redirect()->route('punto-vendita.index')
83 95
                 ->with('error', 'Punto di vendita non trovato');
84 96
         }
97
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
85 98
 
86 99
         if (Auth::user()->can('edit-punto_vendita')) {
87 100
 
@@ -135,13 +148,24 @@ class PuntoVenditaController extends Controller
135 148
             //         }
136 149
             // }
137 150
 
151
+            unset($validated['attivita_id']);
152
+
153
+            if (! empty($validated['endpoint_id'])) {
154
+                $endpoint = \App\Models\Endpoint::find($validated['endpoint_id']);
155
+                if (! $endpoint || (int) $endpoint->attivita_id !== (int) $puntoVendita->attivita_id) {
156
+                    abort(404);
157
+                }
158
+            }
159
+
138 160
             if ($request->has('info')) {
139 161
                 $validated['info'] = json_decode($request->info, true);
140 162
             }
141 163
             if ($request->has('url_stampante')) {
142
-                $validated['endpoint_id'] = Dispositivo::where('id', $validated['url_stampante'])
143
-                    ->where('tipo', Dispositivo::STAMPANTE)->first()->endpoint_id ?? null;
144
-
164
+                $stampante = Dispositivo::where('id', $validated['url_stampante'])
165
+                    ->where('tipo', Dispositivo::STAMPANTE)
166
+                    ->where('attivita_id', $puntoVendita->attivita_id)
167
+                    ->first();
168
+                $validated['endpoint_id'] = $stampante->endpoint_id ?? null;
145 169
             }
146 170
 
147 171
             $puntoVendita->update($validated);
@@ -158,9 +182,20 @@ class PuntoVenditaController extends Controller
158 182
         if (! $puntoVendita) {
159 183
             return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
160 184
         }
185
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
161 186
 
162 187
         if (Auth::user()->can('edit-punto_vendita')) {
163
-            $cucine_ids = $request->get('cucine_ids');
188
+            $cucine_ids = array_values(array_filter(array_map('intval', (array) $request->get('cucine_ids', []))));
189
+            if ($cucine_ids !== []) {
190
+                $cucine = Cucina::query()
191
+                    ->whereIn('id', $cucine_ids)
192
+                    ->get();
193
+                if ($cucine->count() !== count($cucine_ids)
194
+                    || $cucine->contains(fn ($cucina) => (int) $cucina->attivita_id !== (int) $puntoVendita->attivita_id)
195
+                ) {
196
+                    abort(404);
197
+                }
198
+            }
164 199
             $puntoVendita->hasCucine()->sync($cucine_ids);
165 200
 
166 201
             return response()->json(['success' => true, 'message' => 'Cucine associate con successo']);
@@ -210,7 +245,8 @@ class PuntoVenditaController extends Controller
210 245
             return redirect()->route('punto-vendita.index')
211 246
                 ->with('error', 'Punto di vendita non trovato');
212 247
         }
213
-
248
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
249
+        
214 250
         if($puntoVendita->attivita->user_id != Auth::user()->id){
215 251
             session(['attivita_attuale' => null]);
216 252
             Cookie::queue(Cookie::forget('binding_token'));
@@ -285,8 +321,6 @@ class PuntoVenditaController extends Controller
285 321
                     if ($isDataTableDrawRequest) {
286 322
                         // Prosegue senza interrompere la risposta DataTable.
287 323
                     } else {
288
-                        dd('11, altro dispositivo', json_encode(request()->cookie()));
289
-
290 324
                         return redirect()->route('punto-vendita.index')->with('error', 'Dispositivo già occupato. Dissociare per potervi accedere.');
291 325
                     }
292 326
                 }
@@ -346,7 +380,8 @@ class PuntoVenditaController extends Controller
346 380
         if (! $puntoVendita) {
347 381
             return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
348 382
         }
349
-
383
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
384
+        
350 385
         Cookie::queue(Cookie::forget('binding_token'));
351 386
 
352 387
         $puntoVendita->binding_token = null;
@@ -363,6 +398,7 @@ class PuntoVenditaController extends Controller
363 398
             return redirect()->route('punto-vendita.kiosk.index')
364 399
                 ->with('error', 'Ordine non trovato');
365 400
         }
401
+        AttivitaService::garantisciAttivita($ordine->attivita_id);
366 402
 
367 403
         return view('punto_vendita.kiosk.riepilogo', ['ordine' => $ordine]);
368 404
     }
@@ -374,7 +410,8 @@ class PuntoVenditaController extends Controller
374 410
             return redirect()->route('punto-vendita.index')
375 411
                 ->with('error', 'Punto di vendita non trovato');
376 412
         }
377
-
413
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
414
+        
378 415
         return view('punto_vendita.dettagli', ['puntoVendita' => $puntoVendita]);
379 416
     }
380 417
 
@@ -385,17 +422,18 @@ class PuntoVenditaController extends Controller
385 422
             return redirect()->route('punto-vendita.index')
386 423
                 ->with('error', 'Punto di vendita non trovato');
387 424
         }
388
-        // Calcola la data di oggi
425
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
426
+        
389 427
         $oggi = now()->startOfDay();
390 428
 
391
-        // Recupera tutti gli ordini di oggi per il punto vendita
392
-        $ordiniOggi = \App\Models\Ordine::where('dispositivo_id', $puntoVendita->id)
429
+        // Solo ordini effettivamente pagati (esclude carrelli e tentativi falliti)
430
+        $ordiniOggi = Ordine::query()
431
+            ->where('dispositivo_id', $puntoVendita->id)
432
+            ->where('stato', Ordine::PAGATO)
393 433
             ->whereDate('created_at', $oggi)
394 434
             ->get();
395 435
 
396
-        // Conta il totale ordini di oggi
397 436
         $totaleOrdiniOggi = $ordiniOggi->count();
398
-
399 437
         $ordineIds = $ordiniOggi->pluck('id')->all();
400 438
 
401 439
         if ($ordineIds === []) {
@@ -403,22 +441,21 @@ class PuntoVenditaController extends Controller
403 441
             $pagamentiPerMetodo = [];
404 442
             $pagamentiConteggioPerMetodo = [];
405 443
         } else {
406
-            // Somma importi pagamenti legati agli ordini di oggi di questo punto vendita
407
-            $totaleIncassi = (float) Pagamento::query()
444
+            // Solo pagamenti con stato "pagato" (scopePerIncasso)
445
+            $pagamentiBase = Pagamento::query()
408 446
                 ->whereIn('ordine_id', $ordineIds)
409
-                ->sum('importo');
447
+                ->perIncasso();
410 448
 
411
-            // Raggruppa per metodo_pagamento_id (colonna reale su tabella pagamento)
412
-            $pagamentiPerMetodo = Pagamento::query()
413
-                ->whereIn('ordine_id', $ordineIds)
449
+            $totaleIncassi = (float) (clone $pagamentiBase)->sum('importo');
450
+
451
+            $pagamentiPerMetodo = (clone $pagamentiBase)
414 452
                 ->selectRaw('metodo_pagamento_id, SUM(importo) as totale_importo')
415 453
                 ->groupBy('metodo_pagamento_id')
416 454
                 ->pluck('totale_importo', 'metodo_pagamento_id')
417 455
                 ->map(fn ($v) => (float) $v)
418 456
                 ->all();
419 457
 
420
-            $pagamentiConteggioPerMetodo = Pagamento::query()
421
-                ->whereIn('ordine_id', $ordineIds)
458
+            $pagamentiConteggioPerMetodo = (clone $pagamentiBase)
422 459
                 ->selectRaw('metodo_pagamento_id, COUNT(*) as conteggio')
423 460
                 ->groupBy('metodo_pagamento_id')
424 461
                 ->pluck('conteggio', 'metodo_pagamento_id')
@@ -438,25 +475,30 @@ class PuntoVenditaController extends Controller
438 475
     public function cerca_pre_ordine(Request $request)
439 476
     {
440 477
         $codice = $request->get('codice');
441
-        // $pre_ordine = \App\Models\SaltacodaOrdine::where('codice' , $codice)->first();
442
-        // $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', 'like', '%PRE_'.strtoupper($codice).'%')->first();
443
-        $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', 'like', '%'.strtoupper($codice).'%')->first();
478
+        if($codice == '' || $codice == null) {
479
+            return view('punto_vendita.cassa._partials.pre_ordine', ['success' => false, 'error' => 'Codice pre-ordine non valido']);
480
+        }
481
+        $codice = SaltacodaOrdine::normalizzaCodice($codice);
482
+        if ($codice === '') {
483
+            return view('punto_vendita.cassa._partials.pre_ordine', ['success' => false, 'error' => 'Codice pre-ordine non valido']);
484
+        }
485
+        if (strlen($codice) < 3) {
486
+            return view('punto_vendita.cassa._partials.pre_ordine', ['success' => false, 'error' => 'Inserisci almeno 3 caratteri']);
487
+        }
444 488
 
445
-        // Se non trovato, prova con "PRE_" come prefisso se non già presente
446
-        if (! $pre_ordine && stripos($codice, 'PRE_') !== 0) {
447
-            $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', 'like', '%PRE_'.strtoupper($codice).'%')->first();
489
+        if (! Session::has('attivita_attuale') || Session::get('attivita_attuale') === null) {
490
+            return view('punto_vendita.cassa._partials.pre_ordine', ['success' => false, 'error' => 'Attività non trovata']);
448 491
         }
449 492
 
450
-        if (! $pre_ordine) {
451
-            return view('punto_vendita.cassa._partials.pre_ordine', ['success' => false, 'error' => 'Pre-ordine non trovato']);
493
+        $attivitaId = (int) Session::get('attivita_attuale');
494
+        $query = SaltacodaOrdine::query()->where('attivita_id', $attivitaId);
452 495
 
453
-            // return response()->json(['success' => false, 'message' => 'Pre-ordine non trovato']);
454
-        }
496
+        $pre_ordine = strlen($codice) >= 6
497
+            ? $query->where('codice', $codice)->first()
498
+            : $query->where('codice', 'like', $codice.'%')->first();
455 499
 
456
-        if (! (Session::has('attivita_attuale') && Session::get('attivita_attuale') != null && (int) Session::get('attivita_attuale') == (int) $pre_ordine->attivita_id)) {
457
-            return view('punto_vendita.cassa._partials.pre_ordine', ['success' => false, 'error' => 'Attività non trovata']);
458
-    
459
-        // return response()->json(['success' => false, 'message' => 'Pre-ordine non trovato']);
500
+        if (! $pre_ordine) {
501
+            return view('punto_vendita.cassa._partials.pre_ordine', ['success' => false, 'error' => 'Pre-ordine non trovato']);
460 502
         }
461 503
 
462 504
         return view('punto_vendita.cassa._partials.pre_ordine', ['pre_ordine' => $pre_ordine]);
@@ -467,6 +509,10 @@ class PuntoVenditaController extends Controller
467 509
     public function importa_pre_ordine(Request $request)
468 510
 {
469 511
     $codice = (string) $request->get('codice');
512
+    if($codice == '' || $codice == null) {
513
+        return response()->json(['success' => false, 'message' => 'Codice pre-ordine non valido']);
514
+    }
515
+    $codice = SaltacodaOrdine::normalizzaCodice($codice);
470 516
 
471 517
     if (! Session::has('attivita_attuale') || Session::get('attivita_attuale') === null) {
472 518
         return response()->json(['success' => false, 'message' => 'Attività non trovata']);
@@ -492,6 +538,7 @@ class PuntoVenditaController extends Controller
492 538
             if (! $ordine || $ordine->stato !== Ordine::CARRELLO) {
493 539
                 return response()->json(['success' => false, 'message' => 'Ordine non valido']);
494 540
             }
541
+            AttivitaService::garantisciAttivita($ordine->attivita_id);
495 542
 
496 543
             $isPrimoImport = $pre_ordine->stato === SaltacodaOrdine::PRE_ORDINE;
497 544
             $isRipristino = $pre_ordine->stato === SaltacodaOrdine::PRE_CARRELLO

+ 916
- 166
app/Http/Controllers/ReportController.php
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 2
- 0
app/Http/Controllers/RigaFatturazioneController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use Illuminate\Support\Facades\Storage;
7 9
 use Illuminate\Support\Facades\Validator;

+ 13
- 9
app/Http/Controllers/RigaOrdineController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use Illuminate\Database\Eloquent\Builder;
7 9
 use App\Models\Dispositivo;
@@ -23,19 +25,21 @@ class RigaOrdineController extends Controller
23 25
     public static function middleware(): array
24 26
     {
25 27
         return [
26
-            new Middleware('permission:view-riga_ordine', only: ['index']),
27
-            new Middleware('permission:create-riga_ordine|edit-riga_ordine|delete-riga_ordine', only: ['store', 'update', 'destroy']),
28
+            new Middleware('permission:view-riga_ordine|view-cucina|view-asporto|view-punto_vendita', only: ['index', 'datatable', 'dettagli', 'lista_da_chiamare', 'lista_chiamate']),
29
+            new Middleware('permission:create-riga_ordine|edit-riga_ordine|delete-riga_ordine|view-cucina|view-asporto|view-punto_vendita', only: ['store', 'update', 'destroy', 'chiamata', 'ritiro']),
28 30
         ];
29 31
     }
30 32
 
31
-    public function dettagli(Request $request){
32
-        if($request->has('riga_ordine_id')){
33
-            $riga_ordine = RigaOrdine::find($request->riga_ordine_id);
34
-            if($riga_ordine == null){ return response()->json(['success' => false, 'message' => 'Riga ordine non trovata']); }
35
-            return view('punto_vendita.cassa._partials.carrello.cmd_carrello', ['cmd' => 'dettagli', 'riga_ordine_id' => $riga_ordine->id]);
33
+    public function dettagli(Request $request)
34
+    {
35
+        if (! $request->has('riga_ordine_id')) {
36
+            return response()->json(['success' => false, 'message' => 'ID non valido']);
36 37
         }
37
-        return response()->json(['success' => false, 'message' => 'ID non valido']);
38
-        
38
+
39
+        $riga_ordine = app(\App\Services\Carrello\CarrelloService::class)
40
+            ->rigaDiQuestaCassa((int) $request->riga_ordine_id);
41
+
42
+        return view('punto_vendita.cassa._partials.carrello.cmd_carrello', ['cmd' => 'dettagli', 'riga_ordine_id' => $riga_ordine->id]);
39 43
     }
40 44
 
41 45
     public function lista_da_chiamare(Request $request){

+ 2
- 2
app/Http/Controllers/RigaOrdineNotificaController.php Просмотреть файл

@@ -11,12 +11,12 @@ class RigaOrdineNotificaController extends Controller
11 11
     public function salva_fcm_token(Request $request)
12 12
     {
13 13
         $request->validate([
14
-            'ordine_id' => 'required|integer',
14
+            'ordine_codice' => 'required|string',
15 15
             'fcm_token' => 'required|string',
16 16
         ]);
17 17
 
18 18
         $ordine = Ordine::query()
19
-            ->where('id', $request->input('ordine_id'))
19
+            ->where('codice', $request->input('ordine_codice'))
20 20
             ->where('stato', Ordine::PAGATO)
21 21
             ->first();
22 22
 

+ 3
- 1
app/Http/Controllers/RoleController.php Просмотреть файл

@@ -33,7 +33,9 @@ class RoleController extends Controller implements HasMiddleware
33 33
   public static function middleware(): array
34 34
   {
35 35
     return [
36
-      new Middleware('permission:view-role', only: ['index']),
36
+      new Middleware('permission:view-role', only: ['index', 'showEdit', 'showNew', 'getPermissions']),
37
+      new Middleware('permission:create-role', only: ['createRole']),
38
+      new Middleware('permission:edit-role', only: ['updatePermission']),
37 39
       new Middleware('permission:create-role|edit-role|remove-role', only: ['store']),
38 40
     ];
39 41
   }

+ 334
- 60
app/Http/Controllers/SaltacodaController.php Просмотреть файл

@@ -2,16 +2,20 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Attivita;
7 9
 use App\Models\Cucina;
8 10
 use App\Models\Piatto;
9 11
 use App\Models\Saltacoda;
10 12
 use App\Models\SaltacodaOrdine;
11
-use App\Models\SaltacodaRigaordine;
13
+use App\Models\SaltacodaRigaOrdine;
12 14
 use App\Models\VariantePiatto;
13 15
 use App\Models\SaltacodaRigaOrdineHasVariante;
14 16
 use Illuminate\Support\Facades\DB;
17
+use Illuminate\Support\Str;
18
+use App\Services\Attivita\AttivitaService;
15 19
 
16 20
 
17 21
 class SaltacodaController extends Controller
@@ -28,7 +32,7 @@ class SaltacodaController extends Controller
28 32
     {
29 33
         return [
30 34
             new Middleware('permission:view-saltacoda', only: ['index']),
31
-            new Middleware('permission:create-saltacoda|edit-saltacoda|delete-saltacoda', only: ['store', 'update', 'destroy']),
35
+            new Middleware('permission:create-saltacoda|edit-saltacoda|delete-saltacoda', only: ['store', 'update', 'destroy', 'attiva']),
32 36
         ];
33 37
     }
34 38
 
@@ -76,6 +80,8 @@ class SaltacodaController extends Controller
76 80
             'istruzioni' => 'nullable|json',
77 81
         ]);
78 82
 
83
+        AttivitaService::garantisciAttivita($request->attivita_id);
84
+
79 85
         $saltacoda = Saltacoda::updateOrCreate(
80 86
             ['attivita_id' => $request->attivita_id],
81 87
             [
@@ -90,9 +96,11 @@ class SaltacodaController extends Controller
90 96
         return redirect()->route('saltacoda.index')->with('success', 'Saltacoda salvato');
91 97
     }
92 98
 
93
-    public function show(Request $request)
99
+
100
+    ///METODI CLIENTE NON AUTENTICATI
101
+    public function show(Request $request, $slug)
94 102
     {
95
-        $attivita = Attivita::find($request->get('attivita_id'));
103
+        $attivita = Attivita::where('slug', $slug)->first();
96 104
         if(!$attivita) {
97 105
             return response()->json([
98 106
                 'success' => false,
@@ -176,6 +184,21 @@ class SaltacodaController extends Controller
176 184
             }
177 185
         }
178 186
 
187
+        $ordineInModifica = null;
188
+        $avvisiModifica = null;
189
+        if ($request->filled('codice')) {
190
+            $preOrdine = $this->trovaPreOrdineModificabile(
191
+                $request->get('codice'),
192
+                (int) $attivita->id,
193
+                false,
194
+                $this->tokenCliente($request)
195
+            );
196
+            if ($preOrdine) {
197
+                $avvisiModifica = $this->analizzaOrdineNonValido($preOrdine);
198
+                $ordineInModifica = $this->serializzaPreOrdinePerModifica($preOrdine);
199
+            }
200
+        }
201
+
179 202
         return view('saltacoda.show', [
180 203
             'attivita' => $attivita,
181 204
             'cucine' => $cucine,
@@ -183,11 +206,13 @@ class SaltacodaController extends Controller
183 206
             'saltacoda_id' => $saltacoda->id,
184 207
             'varianti_per_piatto' => $variantiPerPiatto,
185 208
             'varianti_per_cucina' => $variantiPerCucina,
209
+            'ordine_in_modifica' => $ordineInModifica,
210
+            'avvisi_modifica' => $avvisiModifica,
186 211
         ]);
187 212
     }
188 213
 
189 214
     public function pre_ordine_salva(Request $request)
190
-    {
215
+    {       
191 216
         $request->validate([
192 217
             'saltacoda_id' => 'required|exists:saltacoda,id',
193 218
             'attivita_id' => 'required|exists:attivita,id',
@@ -199,6 +224,8 @@ class SaltacodaController extends Controller
199 224
             'riga_ordine.*.varianti.*' => 'integer|exists:variante_piatto,id',
200 225
             'info_cliente' => 'nullable|array',
201 226
             'idempotency_key' => 'nullable|string|max:120',
227
+            'codice' => 'nullable|string|max:9',
228
+            't' => 'nullable|string|max:64',
202 229
         ]);
203 230
 
204 231
         $saltacoda = Saltacoda::where('id', $request->saltacoda_id)
@@ -211,18 +238,37 @@ class SaltacodaController extends Controller
211 238
             ], 422);
212 239
         }
213 240
 
241
+        $isModifica = $request->filled('codice');
242
+
214 243
         try {
215
-            $saltacoda_ordine = DB::transaction(function () use ($request) {
216
-                $saltacoda_ordine = SaltacodaOrdine::firstOrNew([
217
-                    'riferimento' => $request->idempotency_key,
218
-                ]);
244
+            $saltacoda_ordine = DB::transaction(function () use ($request, $isModifica) {
245
+                if ($isModifica) {
246
+                    $saltacoda_ordine = $this->trovaPreOrdineModificabile(
247
+                        $request->codice,
248
+                        (int) $request->attivita_id,
249
+                        true,
250
+                        $this->tokenCliente($request)
251
+                    );
252
+
253
+                    if (!$saltacoda_ordine) {
254
+                        throw new \InvalidArgumentException('Questo pre-ordine non può più essere modificato.');
255
+                    }
256
+                } else {
257
+                    $saltacoda_ordine = SaltacodaOrdine::firstOrNew([
258
+                        'riferimento' => $request->idempotency_key,
259
+                    ]);
260
+
261
+                    if (!$saltacoda_ordine->exists) {
262
+                        $saltacoda_ordine->codice = $this->genera_codice_saltacoda();
263
+                        $saltacoda_ordine->token = Str::random(32);
264
+                    } elseif (! filled($saltacoda_ordine->token)) {
265
+                        $saltacoda_ordine->token = Str::random(32);
266
+                    }
219 267
 
220
-                if (!$saltacoda_ordine->exists) {
221
-                    $saltacoda_ordine->codice = $this->genera_codice_saltacoda();
268
+                    $saltacoda_ordine->riferimento = $request->idempotency_key;
222 269
                 }
223 270
 
224 271
                 $saltacoda_ordine->fill([
225
-                    'riferimento' => $request->idempotency_key,
226 272
                     'attivita_id' => $request->attivita_id,
227 273
                     'info' => $request->info_cliente,
228 274
                     'prenotazione_id' => null,
@@ -236,49 +282,7 @@ class SaltacodaController extends Controller
236 282
                 $saltacoda_ordine->save();
237 283
 
238 284
                 $saltacoda_ordine->saltacoda_riga_ordine()->delete();
239
-
240
-                foreach ($request->riga_ordine as $riga) {
241
-                    $piatto = Piatto::query()
242
-                        ->where('id', $riga['piatto_id'])
243
-                        ->where('attivita_id', $request->attivita_id)
244
-                        ->first();
245
-
246
-                    if (!$piatto) {
247
-                        throw new \InvalidArgumentException('Piatto non valido per questa attività.');
248
-                    }
249
-
250
-                    $qta = (int) $riga['qta'];
251
-                    $varianteIds = collect($riga['varianti'] ?? [])->unique()->values();
252
-                    $varianti = $varianteIds->isEmpty()
253
-                        ? collect()
254
-                        : VariantePiatto::query()
255
-                            ->where('attivita_id', $request->attivita_id)
256
-                            ->where('is_attivo', true)
257
-                            ->whereIn('id', $varianteIds)
258
-                            ->get();
259
-
260
-                    if ($varianteIds->count() !== $varianti->count()) {
261
-                        throw new \InvalidArgumentException('Una o più varianti non sono valide per questa attività.');
262
-                    }
263
-
264
-                    $prezzoRiga = $this->calcolaPrezzoRigaSaltacoda($piatto, $qta, $varianti);
265
-
266
-                    $saltacoda_riga = SaltacodaRigaordine::create([
267
-                        'saltacoda_ordine_id' => $saltacoda_ordine->id,
268
-                        'piatto_id' => $piatto->id,
269
-                        'quantita' => $qta,
270
-                        'note' => $riga['note'] ?? null,
271
-                        'prezzo' => $prezzoRiga,
272
-                    ]);
273
-
274
-                    foreach ($varianti as $variante) {
275
-                        SaltacodaRigaOrdineHasVariante::create([
276
-                            'saltacoda_riga_ordine_id' => $saltacoda_riga->id,
277
-                            'variante_id' => $variante->id,
278
-                            'nota' => null,
279
-                        ]);
280
-                    }
281
-                }
285
+                $this->salvaRighePreOrdine($saltacoda_ordine, $request);
282 286
 
283 287
                 $saltacoda_ordine->prezzo = $saltacoda_ordine->saltacoda_riga_ordine()->sum('prezzo');
284 288
                 $saltacoda_ordine->save();
@@ -289,11 +293,29 @@ class SaltacodaController extends Controller
289 293
                 ]);
290 294
             });
291 295
 
292
-            return response()->json([
296
+            $json = response()->json([
293 297
                 'success' => true,
294
-                'message' => 'Pre-ordine salvato',
298
+                'message' => $isModifica ? 'Pre-ordine aggiornato' : 'Pre-ordine salvato',
295 299
                 'data' => $saltacoda_ordine,
300
+                'token' => $saltacoda_ordine->token,
296 301
             ]);
302
+
303
+            if (filled($saltacoda_ordine->token)) {
304
+                $json->cookie(
305
+                    'saltacoda_token',
306
+                    $saltacoda_ordine->token,
307
+                    60 * 12,
308
+                    '/',
309
+                    null,
310
+                    false,
311
+                    true,
312
+                    false,
313
+                    'lax'
314
+                );
315
+            }
316
+
317
+            return $json;
318
+
297 319
         } catch (\InvalidArgumentException $exception) {
298 320
             return response()->json([
299 321
                 'success' => false,
@@ -304,18 +326,270 @@ class SaltacodaController extends Controller
304 326
 
305 327
     public function pre_ordine_show(Request $request)
306 328
     {
329
+        if($request->get('codice') === '' || $request->get('codice') == '' || $request->get('codice') == null) {
330
+            return abort(404);
331
+        }
332
+        $codice = SaltacodaOrdine::normalizzaCodice($request->get('codice'));
333
+        $token = $this->tokenCliente($request);
334
+        if ($codice === '' || $token === '') {
335
+            return abort(404);
336
+        }
337
+
307 338
         $saltacoda_ordine = SaltacodaOrdine::query()
308 339
             ->with([
309 340
                 'saltacoda_riga_ordine.piatto',
310 341
                 'saltacoda_riga_ordine.saltacoda_has_variante.variante_piatto',
311 342
                 'attivita',
312 343
             ])
313
-            ->where('codice', $request->get('codice'))
344
+            ->where('codice', $codice)
345
+            ->where('token', $token)
314 346
             ->first();
315 347
         if(!$saltacoda_ordine) {
316 348
             return abort(404);
317 349
         }
318
-        return view('saltacoda.pre_ordine', ['saltacoda_ordine' => $saltacoda_ordine]);
350
+
351
+        $avvisiModifica = null;
352
+        if ($saltacoda_ordine->stato === SaltacodaOrdine::PRE_ORDINE) {
353
+            $avvisiModifica = $this->analizzaOrdineNonValido($saltacoda_ordine);
354
+        }
355
+
356
+        return view('saltacoda.pre_ordine', [
357
+            'saltacoda_ordine' => $saltacoda_ordine,
358
+            'modificabile' => $saltacoda_ordine->stato === SaltacodaOrdine::PRE_ORDINE,
359
+            'avvisi_modifica' => $avvisiModifica,
360
+        ]);
361
+    }
362
+
363
+
364
+    ///METODI PRIVATI
365
+
366
+    private function tokenCliente(Request $request): string
367
+    {
368
+        return trim((string) ($request->cookie('saltacoda_token') ?: $request->input('t') ?: ''));
369
+    }
370
+
371
+    private function trovaPreOrdineModificabile(?string $codice, int $attivitaId, bool $lock = false, ?string $token = null): ?SaltacodaOrdine
372
+    {
373
+        $codice = SaltacodaOrdine::normalizzaCodice($codice);
374
+        $token = trim((string) $token);
375
+        if ($codice === '' || $token === '') {
376
+            return null;
377
+        }
378
+
379
+        $query = SaltacodaOrdine::query()
380
+            ->with([
381
+                'saltacoda_riga_ordine.piatto',
382
+                'saltacoda_riga_ordine.saltacoda_has_variante.variante_piatto',
383
+            ])
384
+            ->where('codice', $codice)
385
+            ->where('token', $token)
386
+            ->where('attivita_id', $attivitaId)
387
+            ->where('stato', SaltacodaOrdine::PRE_ORDINE);
388
+
389
+        if ($lock) {
390
+            $query->lockForUpdate();
391
+        }
392
+
393
+        return $query->first();
394
+    }
395
+
396
+    private function analizzaOrdineNonValido(SaltacodaOrdine $ordine): array
397
+    {
398
+        $ordine->loadMissing([
399
+            'saltacoda_riga_ordine.piatto',
400
+            'saltacoda_riga_ordine.saltacoda_has_variante.variante_piatto',
401
+        ]);
402
+
403
+        $piattiRimossi = [];
404
+        $variantiRimosse = [];
405
+
406
+        foreach ($ordine->saltacoda_riga_ordine as $riga) {
407
+            $piatto = $riga->piatto;
408
+            $nomePiatto = $piatto?->nome ?? ('Piatto #' . $riga->piatto_id);
409
+
410
+            if (!$piatto || !$piatto->is_attivo) {
411
+                $piattiRimossi[] = [
412
+                    'nome' => $nomePiatto,
413
+                    'qta' => (int) $riga->quantita,
414
+                ];
415
+                continue;
416
+            }
417
+
418
+            foreach ($riga->saltacoda_has_variante as $hasVariante) {
419
+                $variante = $hasVariante->variante_piatto;
420
+                if (!$variante || !$variante->is_attivo) {
421
+                    $variantiRimosse[] = [
422
+                        'piatto' => $nomePiatto,
423
+                        'label' => $variante?->label ?? 'Opzione',
424
+                    ];
425
+                }
426
+            }
427
+        }
428
+
429
+        return [
430
+            'piatti_rimossi' => $piattiRimossi,
431
+            'varianti_rimosse' => $variantiRimosse,
432
+            'ha_problemi' => $piattiRimossi !== [] || $variantiRimosse !== [],
433
+        ];
434
+    }
435
+
436
+    private function pulisciOrdineNonValido(SaltacodaOrdine $ordine): array
437
+    {
438
+        $avvisi = $this->analizzaOrdineNonValido($ordine);
439
+        if (!$avvisi['ha_problemi']) {
440
+            return $avvisi;
441
+        }
442
+
443
+        $ordine->loadMissing([
444
+            'saltacoda_riga_ordine.piatto',
445
+            'saltacoda_riga_ordine.saltacoda_has_variante.variante_piatto',
446
+        ]);
447
+
448
+        $dirty = false;
449
+
450
+        foreach ($ordine->saltacoda_riga_ordine as $riga) {
451
+            $piatto = $riga->piatto;
452
+
453
+            if (!$piatto || !$piatto->is_attivo) {
454
+                $riga->saltacoda_has_variante()->delete();
455
+                $riga->delete();
456
+                $dirty = true;
457
+                continue;
458
+            }
459
+
460
+            $rigaDirty = false;
461
+            foreach ($riga->saltacoda_has_variante as $hasVariante) {
462
+                $variante = $hasVariante->variante_piatto;
463
+                if (!$variante || !$variante->is_attivo) {
464
+                    $hasVariante->delete();
465
+                    $rigaDirty = true;
466
+                    $dirty = true;
467
+                }
468
+            }
469
+
470
+            if ($rigaDirty) {
471
+                $riga->load('saltacoda_has_variante.variante_piatto');
472
+                $variantiValide = $riga->saltacoda_has_variante
473
+                    ->map(fn ($hasVariante) => $hasVariante->variante_piatto)
474
+                    ->filter();
475
+
476
+                $riga->prezzo = $this->calcolaPrezzoRigaSaltacoda(
477
+                    $piatto,
478
+                    (int) $riga->quantita,
479
+                    $variantiValide
480
+                );
481
+                $riga->save();
482
+            }
483
+        }
484
+
485
+        if ($dirty) {
486
+            $ordine->prezzo = $ordine->saltacoda_riga_ordine()->sum('prezzo');
487
+            $ordine->save();
488
+        }
489
+
490
+        return $avvisi;
491
+    }
492
+
493
+    private function serializzaPreOrdinePerModifica(SaltacodaOrdine $ordine): array
494
+    {
495
+        $ordine->loadMissing([
496
+            'saltacoda_riga_ordine.piatto',
497
+            'saltacoda_riga_ordine.saltacoda_has_variante.variante_piatto',
498
+        ]);
499
+
500
+        $righe = [];
501
+        foreach ($ordine->saltacoda_riga_ordine as $riga) {
502
+            $piatto = $riga->piatto;
503
+            if (!$piatto || !$piatto->is_attivo) {
504
+                continue;
505
+            }
506
+
507
+            $varianti = [];
508
+            foreach ($riga->saltacoda_has_variante as $hasVariante) {
509
+                $variante = $hasVariante->variante_piatto;
510
+                if (!$variante || !$variante->is_attivo) {
511
+                    continue;
512
+                }
513
+
514
+                $varianti[] = [
515
+                    'id' => $variante->id,
516
+                    'label' => $variante->label,
517
+                    'prezzo' => (float) $variante->prezzo,
518
+                    'scope' => filled($variante->piatto_id) ? 'piatto' : 'cucina',
519
+                ];
520
+            }
521
+
522
+            $righe[] = [
523
+                'piatto_id' => $riga->piatto_id,
524
+                'cucina_id' => $piatto->cucina_id,
525
+                'nome' => $piatto->nome,
526
+                'qta' => (int) $riga->quantita,
527
+                'note' => $riga->note ?? '',
528
+                'prezzo_base' => (float) $piatto->prezzo,
529
+                'varianti' => $varianti,
530
+            ];
531
+        }
532
+
533
+        $info = $ordine->info;
534
+        if (is_string($info)) {
535
+            $decoded = json_decode($info, true);
536
+            $info = is_array($decoded) ? $decoded : [];
537
+        }
538
+        if (!is_array($info)) {
539
+            $info = [];
540
+        }
541
+
542
+        return [
543
+            'codice' => $ordine->codice,
544
+            'info_cliente' => $info,
545
+            'righe' => $righe,
546
+        ];
547
+    }
548
+
549
+    private function salvaRighePreOrdine(SaltacodaOrdine $saltacoda_ordine, Request $request): void
550
+    {
551
+        foreach ($request->riga_ordine as $riga) {
552
+            $piatto = Piatto::query()
553
+                ->where('id', $riga['piatto_id'])
554
+                ->where('attivita_id', $request->attivita_id)
555
+                ->first();
556
+
557
+            if (!$piatto) {
558
+                throw new \InvalidArgumentException('Piatto non valido per questa attività.');
559
+            }
560
+
561
+            $qta = (int) $riga['qta'];
562
+            $varianteIds = collect($riga['varianti'] ?? [])->unique()->values();
563
+            $varianti = $varianteIds->isEmpty()
564
+                ? collect()
565
+                : VariantePiatto::query()
566
+                    ->where('attivita_id', $request->attivita_id)
567
+                    ->where('is_attivo', true)
568
+                    ->whereIn('id', $varianteIds)
569
+                    ->get();
570
+
571
+            if ($varianteIds->count() !== $varianti->count()) {
572
+                throw new \InvalidArgumentException('Una o più varianti non sono valide per questa attività.');
573
+            }
574
+
575
+            $prezzoRiga = $this->calcolaPrezzoRigaSaltacoda($piatto, $qta, $varianti);
576
+
577
+            $saltacoda_riga = SaltacodaRigaOrdine::create([
578
+                'saltacoda_ordine_id' => $saltacoda_ordine->id,
579
+                'piatto_id' => $piatto->id,
580
+                'quantita' => $qta,
581
+                'note' => $riga['note'] ?? null,
582
+                'prezzo' => $prezzoRiga,
583
+            ]);
584
+
585
+            foreach ($varianti as $variante) {
586
+                SaltacodaRigaOrdineHasVariante::create([
587
+                    'saltacoda_riga_ordine_id' => $saltacoda_riga->id,
588
+                    'variante_id' => $variante->id,
589
+                    'nota' => null,
590
+                ]);
591
+            }
592
+        }
319 593
     }
320 594
 
321 595
     private function calcolaPrezzoRigaSaltacoda(Piatto $piatto, int $qta, $varianti): float
@@ -338,7 +612,7 @@ class SaltacodaController extends Controller
338 612
         $parteLettera = $lettereSicure[rand(0, count($lettereSicure) - 1)];
339 613
         $parteCifre2 = str_pad(strval(rand(0, 99)), 2, '0', STR_PAD_LEFT);
340 614
         $parteCifre3 = str_pad(strval(rand(0, 999)), 3, '0', STR_PAD_LEFT);
341
-        $codice = strtoupper($parteLettera . $parteCifre2 . '-' . $parteCifre3);
615
+        $codice = strtoupper($parteLettera . $parteCifre2 . $parteCifre3);
342 616
 
343 617
         if (SaltacodaOrdine::where('codice', $codice)->exists()) {
344 618
             return $this->genera_codice_saltacoda();

+ 2
- 0
app/Http/Controllers/StampanteController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use Illuminate\Http\Request;
6 8
 use App\Models\Dispositivo;
7 9
 use App\DataTables\StampanteDataTable;

+ 2
- 0
app/Http/Controllers/TavoloController.php Просмотреть файл

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5 7
 use App\Models\Tavolo;
6 8
 use App\DataTables\TavoloDataTable;
7 9
 use App\DataTables\TavoloDataTableEditor;

+ 9
- 2
app/Http/Controllers/TestiController.php Просмотреть файл

@@ -3,6 +3,7 @@
3 3
 namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6
+use Illuminate\Routing\Controllers\Middleware;
6 7
 use App\Models\Testi;
7 8
 use App\DataTables\TestiDataTable;
8 9
 use App\DataTables\TestiDataTableEditor;
@@ -24,7 +25,6 @@ class TestiController extends Controller
24 25
         return [
25 26
             new Middleware('permission:view-testi', only: ['index']),
26 27
             new Middleware('permission:create-testi|edit-testi|delete-testi', only: ['store', 'update', 'destroy']),
27
-            new Middleware('permission:show-testi-cliente', only: ['show_cliente']),
28 28
         ];
29 29
     }
30 30
 
@@ -57,14 +57,21 @@ class TestiController extends Controller
57 57
     {
58 58
         switch($request->get('oggetto')){
59 59
             case 'privacy':
60
+                $attivitaId = (int) ($request->get('attivita_id') ?: Session::get('attivita_attuale'));
61
+                if ($attivitaId <= 0) {
62
+                    abort(404);
63
+                }
60 64
                 $testi = Testi::where('ambiente', 'cliente')
61 65
                 ->where('tipo', 'privacy')
62 66
                 ->where('is_attivo', true)
67
+                ->where('attivita_id', $attivitaId)
63 68
                 ->orderBy('created_at', 'desc')
64 69
                 ->first();
65 70
                 break;
66 71
             default:
67
-                $testi = Testi::find($request->get('testi_id'));
72
+                $testi = Testi::query()
73
+                    ->where('is_attivo', true)
74
+                    ->find($request->get('testi_id'));
68 75
                 break;
69 76
         }
70 77
 

+ 8
- 8
app/Http/Controllers/TombolaController.php Просмотреть файл

@@ -3,10 +3,12 @@
3 3
 namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6
+use Illuminate\Routing\Controllers\Middleware;
6 7
 use App\Models\Tombola;
7 8
 use Illuminate\Support\Facades\Session;
8 9
 use Illuminate\Support\Facades\Auth;
9 10
 use App\Models\Attivita;
11
+use App\Services\Attivita\AttivitaService;
10 12
 
11 13
 class TombolaController extends Controller
12 14
 {
@@ -21,8 +23,8 @@ class TombolaController extends Controller
21 23
     public static function middleware(): array
22 24
     {
23 25
         return [
24
-            new Middleware('permission:view-tombola', only: ['index']),
25
-            new Middleware('permission:create-tombola|edit-tombola|delete-tombola', only: ['getTabellone', 'estrai', 'azzera', 'estratti']),
26
+            new Middleware('permission:view-tombola', only: ['index', 'tabellone']),
27
+            new Middleware('permission:create-tombola|edit-tombola|delete-tombola', only: ['getTabellone', 'estrai', 'azzera']),
26 28
         ];
27 29
     }
28 30
     public function getTabellone(Request $request, $attivita_id){
@@ -30,6 +32,7 @@ class TombolaController extends Controller
30 32
         if(!$attivita){
31 33
             return redirect()->route('tombola.index')->with('error', 'Attivita non trovata.');
32 34
         }
35
+        AttivitaService::garantisciAttivita($attivita->id);
33 36
         if(!Auth::user()->can('create-tombola')){
34 37
             return redirect()->route('tombola.index')->with('error', 'Non hai permesso di creare il tabellone.');
35 38
         }
@@ -73,13 +76,12 @@ class TombolaController extends Controller
73 76
     public function tabellone(Request $request, $attivita_id){
74 77
         if(!Auth::user()->can('view-tombola')){
75 78
             return redirect()->route('tombola.index')->with('error', 'Non hai permesso di vedere il tabellone.');
76
-        }elseif(!Attivita::find($attivita_id)->user_id == Auth::user()->id){
77
-            return redirect()->route('tombola.index')->with('error', 'Non sei autorizzato a vedere il tabellone di questa attività.');
78 79
         }
79 80
         $attivita = Attivita::find($attivita_id);
80 81
         if(!$attivita){
81 82
             return redirect()->route('tombola.index')->with('error', 'Attivita non trovata.');
82 83
         }
84
+        AttivitaService::garantisciAttivita($attivita->id);
83 85
         return view('tombola.tabellone', [
84 86
             'attivita' => $attivita,
85 87
         ]);
@@ -90,10 +92,9 @@ class TombolaController extends Controller
90 92
         if(!$attivita){
91 93
             return redirect()->route('tombola.index')->with('error', 'Attivita non trovata.');
92 94
         }
95
+        AttivitaService::garantisciAttivita($attivita->id);
93 96
         if(!Auth::user()->can('view-tombola')){
94 97
             return redirect()->route('tombola.index')->with('error', 'Non hai permesso di estrarre numeri.');
95
-        }elseif($attivita->user_id != Auth::user()->id){
96
-            return redirect()->route('tombola.index')->with('error', 'Non sei autorizzato a estrarre numeri da questa attività.');
97 98
         }
98 99
         $tabellone = Tombola::where('attivita_id', $attivita_id);
99 100
         $tombola = $tabellone->where('estratto', false)->inRandomOrder()->first();
@@ -165,10 +166,9 @@ class TombolaController extends Controller
165 166
         if(!$attivita){
166 167
             return redirect()->route('tombola.index')->with('error', 'Attivita non trovata.');
167 168
         }
169
+        AttivitaService::garantisciAttivita($attivita->id);
168 170
         if(!Auth::user()->can('delete-tombola')){
169 171
             return redirect()->route('tombola.index')->with('error', 'Non hai permesso di azzerare la tombola.');
170
-        }elseif($attivita->user_id != Auth::user()->id){
171
-            return redirect()->route('tombola.index')->with('error', 'Non sei autorizzato a azzerare la tombola di questa attività.');
172 172
         }
173 173
 
174 174
         Tombola::where('attivita_id', $attivita_id)->update([

+ 3
- 1
app/Http/Controllers/UserController.php Просмотреть файл

@@ -50,7 +50,9 @@ class UserController extends Controller implements HasMiddleware
50 50
   public static function middleware(): array
51 51
   {
52 52
     return [
53
-      new Middleware('permission:view-user', only: ['index']),
53
+      new Middleware('permission:view-user', only: ['index', 'admin_list']),
54
+      new Middleware('permission:create-user', only: ['create']),
55
+      new Middleware('permission:edit-user', only: ['edit_profilo', 'updateProfile', 'upload_foto_profilo', 'showCropImage', 'cropImage']),
54 56
       new Middleware('permission:create-user|edit-user|remove-user', only: ['store', 'admin_aggiorna']),
55 57
       new Middleware('role:superadmin', only: ['superadmin_impersonate']),
56 58
     ];

+ 0
- 0
app/Http/Controllers/VariantePiattoController.php Просмотреть файл


Некоторые файлы не были показаны из-за большого количества измененных файлов

Загрузка…
Отмена
Сохранить