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 파일 보기

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
 use Yajra\DataTables\DataTablesEditor;
8
 use Yajra\DataTables\DataTablesEditor;
9
 use Illuminate\Http\Request;
9
 use Illuminate\Http\Request;
10
 use Illuminate\Validation\ValidationException;
10
 use Illuminate\Validation\ValidationException;
11
+use Illuminate\Http\UploadedFile;
12
+use Illuminate\Support\Facades\Auth;
11
 use Illuminate\Support\Facades\Storage;
13
 use Illuminate\Support\Facades\Storage;
12
 use Illuminate\Support\Str;
14
 use Illuminate\Support\Str;
13
 use Illuminate\Http\JsonResponse;
15
 use Illuminate\Http\JsonResponse;
83
 
85
 
84
   public function creating(Model $model, array $data): array
86
   public function creating(Model $model, array $data): array
85
   {
87
   {
86
-    // $model->roles()->sync([$data['ruolo_id']]);
87
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
88
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
89
+    $data['user_id'] = Auth::id();
90
+
88
     return $data;
91
     return $data;
89
   }
92
   }
90
 
93
 
91
   public function updating(Model $model, array $data): array
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
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
97
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
98
+    unset($data['user_id']);
99
+
96
     return $data;
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
   public function upload(Request $request): JsonResponse
133
   public function upload(Request $request): JsonResponse
105
   {
134
   {
106
     $this->action = 'upload';
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
     try {
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
       $this->validate($request, $fieldRules, $this->messages(), $this->attributes());
147
       $this->validate($request, $fieldRules, $this->messages(), $this->attributes());
116
 
148
 
117
       $uploadedFile = $request->file('upload');
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
       if (method_exists($this, 'uploaded')) {
166
       if (method_exists($this, 'uploaded')) {
122
         $id = $this->uploaded($id);
167
         $id = $this->uploaded($id);
124
 
169
 
125
       return response()->json([
170
       return response()->json([
126
         'action' => $this->action,
171
         'action' => $this->action,
127
-        'data'   => [],
128
-        'files'  => [
172
+        'data' => [],
173
+        'files' => [
129
           'files' => [
174
           'files' => [
130
             $id => [
175
             $id => [
131
-              'filename'      => $id,
176
+              'filename' => $id,
132
               'original_name' => $uploadedFile->getClientOriginalName(),
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
       ]);
188
       ]);
144
     } catch (ValidationException $exception) {
189
     } catch (ValidationException $exception) {
145
       return response()->json([
190
       return response()->json([
146
-        'action'      => $this->action,
147
-        'data'        => [],
191
+        'action' => $this->action,
192
+        'data' => [],
148
         'fieldErrors' => [
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
   public function messages(): array
227
   public function messages(): array
159
   {
228
   {
160
     return $this->messages;
229
     return $this->messages;

+ 6
- 1
app/DataTables/BachecaDataTable.php 파일 보기

43
      */
43
      */
44
     public function query(Bacheca $model): QueryBuilder
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
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Bacheca;
5
 use App\Models\Bacheca;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class BachecaDataTableEditor extends DataTablesEditor
11
 class BachecaDataTableEditor extends DataTablesEditor
15
 {
12
 {
76
 
73
 
77
   public function creating(Model $model, array $data): array
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
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
78
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
81
     return $data;
79
     return $data;
82
   }
80
   }
83
 
81
 
84
   public function updating(Model $model, array $data): array
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
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
86
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
89
     return $data;
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
   public function messages(): array
96
   public function messages(): array
92
   {
97
   {
93
     return $this->messages;
98
     return $this->messages;

+ 14
- 8
app/DataTables/CategoriacontabileDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Categoriacontabile;
5
 use App\Models\Categoriacontabile;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
8
+use Illuminate\Support\Facades\Session;
7
 use Illuminate\Validation\Rule;
9
 use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class CategoriacontabileDataTableEditor extends DataTablesEditor
12
 class CategoriacontabileDataTableEditor extends DataTablesEditor
15
 {
13
 {
35
       'nome'  => [
33
       'nome'  => [
36
         'required',
34
         'required',
37
         Rule::unique('categoria_contabile', 'nome')
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
       'descrizione' => 'nullable',
38
       'descrizione' => 'nullable',
41
       'is_attiva' => 'boolean',
39
       'is_attiva' => 'boolean',
83
 
81
 
84
   public function creating(Model $model, array $data): array
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
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
86
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
88
     return $data;
87
     return $data;
89
   }
88
   }
90
 
89
 
91
   public function updating(Model $model, array $data): array
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
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
94
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
96
     return $data;
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
   public function messages(): array
104
   public function messages(): array
99
   {
105
   {
100
     return $this->messages;
106
     return $this->messages;

+ 6
- 1
app/DataTables/ChiusuraServizioDataTable.php 파일 보기

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

+ 6
- 1
app/DataTables/ContenutoBachecaDataTable.php 파일 보기

46
      */
46
      */
47
     public function query(ContenutoBacheca $model): QueryBuilder
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
         if($this->bacheca_id){
55
         if($this->bacheca_id){
51
             return $model->join('bacheca_has_contenuto', 'contenuto_bacheca.id', '=', 'bacheca_has_contenuto.contenuto_id')->where('bacheca_has_contenuto.bacheca_id', $this->bacheca_id);
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
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\ContenutoBacheca;
5
 use App\Models\ContenutoBacheca;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8
 use Yajra\DataTables\DataTablesEditor;
9
 use Yajra\DataTables\DataTablesEditor;
9
 use Illuminate\Http\Request;
10
 use Illuminate\Http\Request;
10
 use Illuminate\Validation\ValidationException;
11
 use Illuminate\Validation\ValidationException;
79
 
80
 
80
   public function creating(Model $model, array $data): array
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
     return $data;
85
     return $data;
83
   }
86
   }
84
 
87
 
85
   public function updating(Model $model, array $data): array
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
     return $data;
99
     return $data;
89
   }
100
   }
107
 
118
 
108
       $uploadedFile = $request->file('upload');
119
       $uploadedFile = $request->file('upload');
109
       $filename     = $this->getUploadedFilename($field, $uploadedFile);
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
       if (method_exists($this, 'uploaded')) {
131
       if (method_exists($this, 'uploaded')) {
113
         $id = $this->uploaded($id);
132
         $id = $this->uploaded($id);

+ 9
- 5
app/DataTables/CucinaDataTable.php 파일 보기

79
      */
79
      */
80
     public function query(Cucina $model): QueryBuilder
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
             return $model->newQuery()->whereRaw('1 = 0');
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
                         Editor::make()
118
                         Editor::make()
118
                         ->ajax(route('cucina.store'))
119
                         ->ajax(route('cucina.store'))
119
                         ->fields([
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
                           Fields\Boolean::make('is_attiva')->label('Attiva')->default(true),  
122
                           Fields\Boolean::make('is_attiva')->label('Attiva')->default(true),  
122
                           Fields\Text::make('nome')->label('Nome'),
123
                           Fields\Text::make('nome')->label('Nome'),
123
                           Fields\Text::make('descrizione')->label('Descrizione'),
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
                           Fields\Text::make('colore')->label('Colore')->set('attr', ['type' => 'color']),
126
                           Fields\Text::make('colore')->label('Colore')->set('attr', ['type' => 'color']),
126
                           Fields\Boolean::make('coperto_come_piatto')->label('Ogni piatto ordinato corrisponde ad un coperto'),  
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
                             // Fields\Image::make('immagine')->label('Immagine'),
129
                             // Fields\Image::make('immagine')->label('Immagine'),
128
                             // Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::where('is_attiva', true)->pluck('id', 'nome')),
130
                             // Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::where('is_attiva', true)->pluck('id', 'nome')),
129
                         ])
131
                         ])
153
         Column::make('badge_colore')->title('Cucina')->addClass('text-left')->responsivePriority(1),
155
         Column::make('badge_colore')->title('Cucina')->addClass('text-left')->responsivePriority(1),
154
         Column::computed('piatti_count')->title('Piatti')->addClass('text-center'),
156
         Column::computed('piatti_count')->title('Piatti')->addClass('text-center'),
155
         Column::make('coperto_come_piatto')->visible(false),
157
         Column::make('coperto_come_piatto')->visible(false),
158
+        Column::make('stampa_ritiro')->visible(false),
156
         Column::computed('action')
159
         Column::computed('action')
157
         ->title('')
160
         ->title('')
158
         ->exportable(false)
161
         ->exportable(false)
174
             Column::make('stampante_id')->data('stampante_display')->title('Stampante')->addClass('text-center'),
177
             Column::make('stampante_id')->data('stampante_display')->title('Stampante')->addClass('text-center'),
175
             // Column::make('cucina_id')->data('cucina_id_display')->title('Cucina')->addClass('text-center'),
178
             // Column::make('cucina_id')->data('cucina_id_display')->title('Cucina')->addClass('text-center'),
176
             Column::make('coperto_come_piatto')->visible(false),
179
             Column::make('coperto_come_piatto')->visible(false),
180
+            Column::make('stampa_ritiro')->visible(false),
177
             Column::make('action')
181
             Column::make('action')
178
             ->title('')
182
             ->title('')
179
             ->exportable(false)
183
             ->exportable(false)

+ 37
- 12
app/DataTables/CucinaDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Cucina;
5
 use App\Models\Cucina;
6
+use App\Models\Dispositivo;
7
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
8
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class CucinaDataTableEditor extends DataTablesEditor
12
 class CucinaDataTableEditor extends DataTablesEditor
15
 {
13
 {
77
 
75
 
78
   public function creating(Model $model, array $data): array
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
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
82
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
82
-    
83
     $data['info']['coperto_come_piatto'] = filter_var($data['coperto_come_piatto'] ?? false, FILTER_VALIDATE_BOOLEAN);
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
     return $data;
87
     return $data;
88
   }
88
   }
89
 
89
 
90
   public function updating(Model $model, array $data): array
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
     $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
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
     $data['info']['coperto_come_piatto'] = filter_var($data['coperto_come_piatto'] ?? false, FILTER_VALIDATE_BOOLEAN);
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
     return $data;
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
   public function messages(): array
125
   public function messages(): array
101
   {
126
   {
102
     return $this->messages;
127
     return $this->messages;

+ 159
- 0
app/DataTables/CuponDataTable.php 파일 보기

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 파일 보기

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
 
16
 
17
 class DispositivoDataTable extends DataTable
17
 class DispositivoDataTable extends DataTable
18
 {
18
 {
19
+    public ?int $attivita_id = null;
20
+
19
     public function __construct()
21
     public function __construct()
20
     {
22
     {
21
         $this->dataTableVariable = 'dataTable_dispositivo';
23
         $this->dataTableVariable = 'dataTable_dispositivo';
47
      */
49
      */
48
     public function query(Dispositivo $model): QueryBuilder
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
                     ->editor(
81
                     ->editor(
75
                         Editor::make()
82
                         Editor::make()
76
                             ->fields([
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
                                 Fields\Hidden::make('endpoint_id')->label('Endpoint ID'),
85
                                 Fields\Hidden::make('endpoint_id')->label('Endpoint ID'),
79
                                 Fields\Text::make('nome')->label('Nome'),
86
                                 Fields\Text::make('nome')->label('Nome'),
80
                                 Fields\Select2::make('tipo')->label('Tipo')->options(Dispositivo::getTipoDispositivo()->pluck('value', 'label')),
87
                                 Fields\Select2::make('tipo')->label('Tipo')->options(Dispositivo::getTipoDispositivo()->pluck('value', 'label')),

+ 15
- 12
app/DataTables/DispositivoDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Dispositivo;
5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class DispositivoDataTableEditor extends DataTablesEditor
11
 class DispositivoDataTableEditor extends DataTablesEditor
15
 {
12
 {
50
     return [
47
     return [
51
       'nome'  => 'required',
48
       'nome'  => 'required',
52
       'tipo' => 'required',
49
       'tipo' => 'required',
53
-      'attivita_id' => 'required|exists:attivita,id',
54
       'licenza' => 'nullable',
50
       'licenza' => 'nullable',
55
       'url_stampante' => 'nullable',
51
       'url_stampante' => 'nullable',
56
       'ubicazione' => 'nullable',
52
       'ubicazione' => 'nullable',
77
     return [
73
     return [
78
       'nome'  => 'required',
74
       'nome'  => 'required',
79
       'tipo' => 'required',
75
       'tipo' => 'required',
80
-      'attivita_id' => 'required|exists:attivita,id',
81
       'licenza' => 'nullable',
76
       'licenza' => 'nullable',
82
       'url_stampante' => 'nullable',
77
       'url_stampante' => 'nullable',
83
       'ubicazione' => 'nullable',
78
       'ubicazione' => 'nullable',
106
 
101
 
107
   public function creating(Model $model, array $data): array
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
     return $data;
107
     return $data;
112
   }
108
   }
113
 
109
 
114
   public function updating(Model $model, array $data): array
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
     return $data;
122
     return $data;
120
   }
123
   }
121
   public function messages(): array
124
   public function messages(): array

+ 24
- 3
app/DataTables/EndpointDataTableEditor.php 파일 보기

11
 use Illuminate\Validation\ValidationException;
11
 use Illuminate\Validation\ValidationException;
12
 use Illuminate\Support\Facades\Storage;
12
 use Illuminate\Support\Facades\Storage;
13
 use Illuminate\Support\Str;
13
 use Illuminate\Support\Str;
14
+use App\Services\Attivita\AttivitaService;
15
+use Illuminate\Support\Facades\Session;
14
 
16
 
15
 class EndpointDataTableEditor extends DataTablesEditor
17
 class EndpointDataTableEditor extends DataTablesEditor
16
 {
18
 {
81
 
83
 
82
   public function creating(Model $model, array $data): array
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
     return $data;
90
     return $data;
86
   }
91
   }
87
 
92
 
88
   public function updating(Model $model, array $data): array
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
     return $data;
113
     return $data;
93
   }
114
   }
94
 
115
 

+ 68
- 44
app/DataTables/EventoDataTable.php 파일 보기

34
             ->addColumn('stato_display', function($entity){
34
             ->addColumn('stato_display', function($entity){
35
               return view('_partials.available', ['available' => $entity->is_attivo]);
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
             ->setRowId('id');
70
             ->setRowId('id');
62
     }
71
     }
68
      */
77
      */
69
     public function query(Evento $model): QueryBuilder
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
     {
92
     {
79
         $buttons = [];
93
         $buttons = [];
80
         if(Auth::user()->can('create-evento')){
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
                 ->className('btn btn-sm btn-primary mb-4')
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
         return $this->builder()
115
         return $this->builder()
96
                     ->setTableId($this->dataTableVariable)
116
                     ->setTableId($this->dataTableVariable)
135
         return [
155
         return [
136
             Column::make('id')->title('ID')->width('10%')->visible(false),
156
             Column::make('id')->title('ID')->width('10%')->visible(false),
137
             Column::make('stato')->data('stato_display')->title('Stato')->addClass('text-center')->responsivePriority(1)->width('10%'),
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
             // Column::make('descrizione')->title('Descrizione'),
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
             Column::computed('action')
173
             Column::computed('action')
150
                   ->title('')
174
                   ->title('')
151
                   ->exportable(false)
175
                   ->exportable(false)

+ 24
- 4
app/DataTables/EventoDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Evento;
5
 use App\Models\Evento;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Http\JsonResponse;
8
 use Illuminate\Http\JsonResponse;
8
 use Illuminate\Http\UploadedFile;
9
 use Illuminate\Http\UploadedFile;
9
 use Yajra\DataTables\DataTablesEditor;
10
 use Yajra\DataTables\DataTablesEditor;
10
 use Illuminate\Http\Request;
11
 use Illuminate\Http\Request;
11
 use Illuminate\Validation\ValidationException;
12
 use Illuminate\Validation\ValidationException;
13
+use Illuminate\Support\Facades\Session;
12
 use Illuminate\Support\Facades\Storage;
14
 use Illuminate\Support\Facades\Storage;
13
 use Illuminate\Support\Str;
15
 use Illuminate\Support\Str;
14
 
16
 
110
 
112
 
111
   public function creating(Model $model, array $data): array
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
     return $data;
118
     return $data;
115
   }
119
   }
116
 
120
 
117
   public function updating(Model $model, array $data): array
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
     return $data;
133
     return $data;
122
   }
134
   }
123
 
135
 
246
   {
258
   {
247
     $id = $request->input('id');
259
     $id = $request->input('id');
248
     if ($id !== null && $id !== '' && is_numeric($id)) {
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
       return $this->uploadDir.'/'.(int) $id;
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
   protected function getUploadedFilename(string $field, UploadedFile $uploadedFile): string
275
   protected function getUploadedFilename(string $field, UploadedFile $uploadedFile): string

+ 17
- 9
app/DataTables/EventoFormDataTableEditor.php 파일 보기

2
 
2
 
3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
+use App\Models\Evento;
5
 use App\Models\EventoForm;
6
 use App\Models\EventoForm;
7
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
8
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class EventoFormDataTableEditor extends DataTablesEditor
11
 class EventoFormDataTableEditor extends DataTablesEditor
15
 {
12
 {
94
   public function creating(Model $model, array $data): array
91
   public function creating(Model $model, array $data): array
95
   {
92
   {
96
     $eventoId = request()->query('evento_id') ?? request()->input('evento_id');
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
     return $data;
101
     return $data;
102
   }
102
   }
103
 
103
 
104
   public function updating(Model $model, array $data): array
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
     return $data;
116
     return $data;
109
   }
117
   }
110
   public function messages(): array
118
   public function messages(): array

+ 5
- 1
app/DataTables/FatturaDataTable.php 파일 보기

52
      */
52
      */
53
     public function query(Fattura $model): QueryBuilder
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
 
4
 
5
 use App\Models\Fattura;
5
 use App\Models\Fattura;
6
 use Illuminate\Database\Eloquent\Model;
6
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
7
+use Illuminate\Support\Facades\Auth;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class FatturaDataTableEditor extends DataTablesEditor
10
 class FatturaDataTableEditor extends DataTablesEditor
15
 {
11
 {
90
 
86
 
91
   public function creating(Model $model, array $data): array
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
     return $data;
90
     return $data;
95
   }
91
   }
96
 
92
 
97
   public function updating(Model $model, array $data): array
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
     return $data;
108
     return $data;
102
   }
109
   }
103
   public function messages(): array
110
   public function messages(): array

+ 13
- 8
app/DataTables/FornitoreDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Fornitore;
5
 use App\Models\Fornitore;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class FornitoreDataTableEditor extends DataTablesEditor
11
 class FornitoreDataTableEditor extends DataTablesEditor
15
 {
12
 {
88
 
85
 
89
   public function creating(Model $model, array $data): array
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
     return $data;
90
     return $data;
93
   }
91
   }
94
 
92
 
95
   public function updating(Model $model, array $data): array
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
     return $data;
104
     return $data;
100
   }
105
   }
101
   public function messages(): array
106
   public function messages(): array

+ 13
- 9
app/DataTables/ImpostazioniDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Impostazioni;
5
 use App\Models\Impostazioni;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class ImpostazioniDataTableEditor extends DataTablesEditor
11
 class ImpostazioniDataTableEditor extends DataTablesEditor
15
 {
12
 {
114
 
111
 
115
   public function creating(Model $model, array $data): array
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
     return $data;
116
     return $data;
119
   }
117
   }
120
 
118
 
121
   public function updating(Model $model, array $data): array
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
     return $data;
130
     return $data;
127
   }
131
   }
128
   public function messages(): array
132
   public function messages(): array

+ 7
- 4
app/DataTables/MetodoPagamentoDataTable.php 파일 보기

17
 
17
 
18
 class MetodoPagamentoDataTable extends DataTable
18
 class MetodoPagamentoDataTable extends DataTable
19
 {
19
 {
20
+    public ?int $attivita_id = null;
21
+
20
     public function __construct()
22
     public function __construct()
21
     {
23
     {
22
         $this->dataTableVariable = 'dataTable_metodo_pagamento';
24
         $this->dataTableVariable = 'dataTable_metodo_pagamento';
55
      */
57
      */
56
     public function query(MetodoPagamento $model): QueryBuilder
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
             return $model->newQuery()->whereRaw('1 = 0');
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
                     ->editor(
91
                     ->editor(
89
                         Editor::make()
92
                         Editor::make()
90
                             ->fields([
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
                                 Fields\Boolean::make('is_attivo')->label('Attivo')->default(true),
95
                                 Fields\Boolean::make('is_attivo')->label('Attivo')->default(true),
93
                                 Fields\Select2::make('tipo')->label('Tipo')->options(MetodoPagamento::getTipiPagamento()->sortBy('label')->pluck('value' ,'label')),
96
                                 Fields\Select2::make('tipo')->label('Tipo')->options(MetodoPagamento::getTipiPagamento()->sortBy('label')->pluck('value' ,'label')),
94
                                 Fields\Text::make('nome')->label('Nome'),
97
                                 Fields\Text::make('nome')->label('Nome'),

+ 13
- 9
app/DataTables/MetodoPagamentoDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\MetodoPagamento;
5
 use App\Models\MetodoPagamento;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class  MetodoPagamentoDataTableEditor extends DataTablesEditor
11
 class  MetodoPagamentoDataTableEditor extends DataTablesEditor
15
 {
12
 {
58
     return [
55
     return [
59
       'nome'  => 'required',
56
       'nome'  => 'required',
60
       'tipo' => 'required|in:'.MetodoPagamento::getTipiPagamento()->pluck('value')->implode(','),
57
       'tipo' => 'required|in:'.MetodoPagamento::getTipiPagamento()->pluck('value')->implode(','),
61
-      'attivita_id' => 'required|exists:attivita,id',
62
       // 'is_attivo' => 'boolean',
58
       // 'is_attivo' => 'boolean',
63
       // 'is_pubblico' => 'boolean',
59
       // 'is_pubblico' => 'boolean',
64
       'key' => 'nullable',
60
       'key' => 'nullable',
85
 
81
 
86
   public function creating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
86
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
90
     $data['is_pubblico'] = isset($data['is_pubblico']) ? true : false;
87
     $data['is_pubblico'] = isset($data['is_pubblico']) ? true : false;
91
     return $data;
88
     return $data;
93
 
90
 
94
   public function updating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
95
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
99
     $data['is_pubblico'] = isset($data['is_pubblico']) ? true : false;
96
     $data['is_pubblico'] = isset($data['is_pubblico']) ? true : false;
100
     return $data;
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
   public function messages(): array
107
   public function messages(): array
104
   {
108
   {
105
     return $this->messages;
109
     return $this->messages;

+ 17
- 12
app/DataTables/MonitorDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Dispositivo;
5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class MonitorDataTableEditor extends DataTablesEditor
11
 class MonitorDataTableEditor extends DataTablesEditor
15
 {
12
 {
50
     return [
47
     return [
51
       'nome'  => 'required',
48
       'nome'  => 'required',
52
       'tipo' => 'required|in:'.Dispositivo::MONITOR,
49
       'tipo' => 'required|in:'.Dispositivo::MONITOR,
53
-      'attivita_id' => 'required|exists:attivita,id',
54
       'licenza' => 'nullable',
50
       'licenza' => 'nullable',
55
       'url_stampante' => 'nullable',
51
       'url_stampante' => 'nullable',
56
       'ubicazione' => 'nullable',
52
       'ubicazione' => 'nullable',
77
     return [
73
     return [
78
       'nome'  => 'required',
74
       'nome'  => 'required',
79
       'tipo' => 'required|in:'.Dispositivo::MONITOR,
75
       'tipo' => 'required|in:'.Dispositivo::MONITOR,
80
-      'attivita_id' => 'required|exists:attivita,id',
81
       'licenza' => 'nullable',
76
       'licenza' => 'nullable',
82
       'url_stampante' => 'nullable',
77
       'url_stampante' => 'nullable',
83
       'ubicazione' => 'nullable',
78
       'ubicazione' => 'nullable',
106
 
101
 
107
   public function creating(Model $model, array $data): array
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
     return $data;
108
     return $data;
112
   }
109
   }
113
 
110
 
114
   public function updating(Model $model, array $data): array
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
     return $data;
124
     return $data;
120
   }
125
   }
121
   public function messages(): array
126
   public function messages(): array

+ 2
- 0
app/DataTables/OperatoreDataTable.php 파일 보기

15
 
15
 
16
 class OperatoreDataTable extends DataTable
16
 class OperatoreDataTable extends DataTable
17
 {
17
 {
18
+    public ?int $attivita_id = null;
19
+
18
     public function __construct()
20
     public function __construct()
19
     {
21
     {
20
         $this->dataTableVariable = 'dataTable_operatore';
22
         $this->dataTableVariable = 'dataTable_operatore';

+ 14
- 9
app/DataTables/OperatoreDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Operatore;
5
 use App\Models\Operatore;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
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
 use Illuminate\Support\Str;
9
 use Illuminate\Support\Str;
13
-use Illuminate\Support\Facades\Hash;
10
+use Yajra\DataTables\DataTablesEditor;
14
 
11
 
15
 class OperatoreDataTableEditor extends DataTablesEditor
12
 class OperatoreDataTableEditor extends DataTablesEditor
16
 {
13
 {
84
 
81
 
85
   public function creating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
86
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
89
     if(!isset($data['password'])){
87
     if(!isset($data['password'])){
90
       $data['password'] = Str::random(8);
88
       $data['password'] = Str::random(8);
95
 
93
 
96
   public function updating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
98
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
101
     $data['username'] = $this->createUsername($data);
99
     $data['username'] = $this->createUsername($data);
102
     return $data;
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
   public function messages(): array
109
   public function messages(): array
105
   {
110
   {
106
     return $this->messages;
111
     return $this->messages;

+ 32
- 4
app/DataTables/OpzioneFormDataTableEditor.php 파일 보기

2
 
2
 
3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
+use App\Models\EventoForm;
5
 use App\Models\OpzioneForm;
6
 use App\Models\OpzioneForm;
7
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
8
 use Illuminate\Database\Eloquent\Model;
7
 use Yajra\DataTables\DataTablesEditor;
9
 use Yajra\DataTables\DataTablesEditor;
8
 
10
 
40
 
42
 
41
     public function creating(Model $model, array $data): array
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
         return $data;
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
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Ordine;
5
 use App\Models\Ordine;
6
+use App\Models\Prenotazione;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class OrdineDataTableEditor extends DataTablesEditor
12
 class OrdineDataTableEditor extends DataTablesEditor
15
 {
13
 {
91
 
89
 
92
   public function creating(Model $model, array $data): array
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
     return $data;
96
     return $data;
96
   }
97
   }
97
 
98
 
98
   public function updating(Model $model, array $data): array
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
     return $data;
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
   public function messages(): array
126
   public function messages(): array
105
   {
127
   {
106
     return $this->messages;
128
     return $this->messages;

+ 11
- 12
app/DataTables/PagamentoDataTable.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Pagamento;
5
 use App\Models\Pagamento;
6
-use App\Models\Ordine;
7
-use App\Models\Prenotazione;
8
 use App\Models\MetodoPagamento;
6
 use App\Models\MetodoPagamento;
9
-use App\Models\Attivita;
10
 use Illuminate\Database\Eloquent\Builder as QueryBuilder;
7
 use Illuminate\Database\Eloquent\Builder as QueryBuilder;
11
 use Yajra\DataTables\EloquentDataTable;
8
 use Yajra\DataTables\EloquentDataTable;
12
 use Yajra\DataTables\Html\Builder as HtmlBuilder;
9
 use Yajra\DataTables\Html\Builder as HtmlBuilder;
64
      */
61
      */
65
     public function query(Pagamento $model): QueryBuilder
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
             return $model->newQuery()->whereRaw('1 = 0')->orderBy('created_at', 'desc');
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
                     ->editor(
96
                     ->editor(
99
                         Editor::make()
97
                         Editor::make()
100
                             ->fields([
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
                                 Fields\Text::make('importo')->label('Importo'),
102
                                 Fields\Text::make('importo')->label('Importo'),
105
                                 Fields\Text::make('causale')->label('Causale'),
103
                                 Fields\Text::make('causale')->label('Causale'),
106
                                 Fields\Select2::make('stato')->label('Stato')->options(Pagamento::getStati()->pluck('value', 'label')),
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
                                 Fields\Text::make('note')->label('Note'),
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
                     ->initComplete("function(settings, json){
110
                     ->initComplete("function(settings, json){
127
             Column::make('prenotazione_id')->title('Prenotazione')->data('prenotazione_id_display'),
125
             Column::make('prenotazione_id')->title('Prenotazione')->data('prenotazione_id_display'),
128
             Column::make('importo')->title('Importo')->data('importo_display'),
126
             Column::make('importo')->title('Importo')->data('importo_display'),
129
             Column::make('causale')->title('Causale'),
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
             Column::make('note')->title('Note'),
130
             Column::make('note')->title('Note'),
132
             Column::computed('action')
131
             Column::computed('action')
133
                   ->title('')
132
                   ->title('')

+ 141
- 0
app/DataTables/PagamentoDataTableEditor.php 파일 보기

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
      */
80
      */
81
     public function query(Piatto $model): QueryBuilder
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
                 Editor::make()
145
                 Editor::make()
146
                     ->ajax(route('piatto.store'))
146
                     ->ajax(route('piatto.store'))
147
                     ->fields([
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
                         Fields\Text::make('nome')->label('Nome'),
149
                         Fields\Text::make('nome')->label('Nome'),
150
                         Fields\Text::make('descrizione')->label('Descrizione'),
150
                         Fields\Text::make('descrizione')->label('Descrizione'),
151
                         Fields\Select2::make('cucina_id')->label('cucina')
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
                         ->default(isset($this->cucina_id) ? $this->cucina_id : ''),
153
                         ->default(isset($this->cucina_id) ? $this->cucina_id : ''),
154
                         Fields\Text::make('prezzo')->label('Prezzo (€)'),
154
                         Fields\Text::make('prezzo')->label('Prezzo (€)'),
155
                         // Fields\Image::make('immagine')->label('Immagine'),
155
                         // Fields\Image::make('immagine')->label('Immagine'),

+ 28
- 7
app/DataTables/PiattoDataTableEditor.php 파일 보기

2
 
2
 
3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
+use App\Models\Cucina;
5
 use App\Models\Piatto;
6
 use App\Models\Piatto;
6
 use App\Models\PiattoHasAllergene;
7
 use App\Models\PiattoHasAllergene;
8
+use App\Services\Attivita\AttivitaService;
7
 use Illuminate\Database\Eloquent\Model;
9
 use Illuminate\Database\Eloquent\Model;
8
-use Illuminate\Validation\Rule;
9
 use Yajra\DataTables\DataTablesEditor;
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
 class PiattoDataTableEditor extends DataTablesEditor
13
 class PiattoDataTableEditor extends DataTablesEditor
16
 {
14
 {
94
 
92
 
95
   public function creating(Model $model, array $data): array
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
     // L'Editor manda `allergeni` come array di ID selezionati:
99
     // L'Editor manda `allergeni` come array di ID selezionati:
98
     // salviamo la relazione nella pivot `piatto_allergene`, non nella colonna `piatto.allergeni`.
100
     // salviamo la relazione nella pivot `piatto_allergene`, non nella colonna `piatto.allergeni`.
99
     $data['_allergeni_ids'] = $this->normalizeAllergeniIds($data['allergeni'] ?? null);
101
     $data['_allergeni_ids'] = $this->normalizeAllergeniIds($data['allergeni'] ?? null);
101
 
103
 
102
     $data['bacheca_id'] = isset($data['bacheca_id']) ? true : false;
104
     $data['bacheca_id'] = isset($data['bacheca_id']) ? true : false;
103
     $data['in_evidenza'] = isset($data['in_evidenza']) ? true : false;
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
     return $data;
107
     return $data;
106
   }
108
   }
107
 
109
 
108
   public function updating(Model $model, array $data): array
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
     $data['_allergeni_ids'] = $this->normalizeAllergeniIds($data['allergeni'] ?? null);
116
     $data['_allergeni_ids'] = $this->normalizeAllergeniIds($data['allergeni'] ?? null);
111
     unset($data['allergeni']);
117
     unset($data['allergeni']);
112
 
118
 
113
     $data['bacheca_id'] = isset($data['bacheca_id']) ? true : false;
119
     $data['bacheca_id'] = isset($data['bacheca_id']) ? true : false;
114
     $data['in_evidenza'] = isset($data['in_evidenza']) ? true : false;
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
     return $data;
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
   protected function normalizeAllergeniIds(null|array|string $value): array
141
   protected function normalizeAllergeniIds(null|array|string $value): array
121
   {
142
   {
122
     if (is_null($value)) {
143
     if (is_null($value)) {

+ 47
- 33
app/DataTables/PrenotazioneDataTable.php 파일 보기

42
             ->addColumn('stato_display', function($entity){
42
             ->addColumn('stato_display', function($entity){
43
               return view('prenotazione._partials.stato-prenotazione', ['stato' => $entity->stato??'']);
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
             ->setRowId('id');
48
             ->setRowId('id');
46
     }
49
     }
47
 
50
 
52
      */
55
      */
53
     public function query(Prenotazione $model): QueryBuilder
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
     public function html(): HtmlBuilder
73
     public function html(): HtmlBuilder
65
     {
74
     {
66
         $titoloPrenotazioni = 'Prenotazione';
75
         $titoloPrenotazioni = 'Prenotazione';
67
-        if(isset($this->evento_id)){
68
-            $titoloPrenotazioni = 'Prenota per ' . Evento::find($this->evento_id)->nome;
69
-        }
76
+
70
         $buttons = [];
77
         $buttons = [];
71
         if(Auth::user()->can('create-prenotazione')){
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
         if(Auth::user()->can('report-prenotazione') || Auth::user()->can('segna-presenza-prenotazione')){
104
         if(Auth::user()->can('report-prenotazione') || Auth::user()->can('segna-presenza-prenotazione')){
105
+            if($this->evento_id){
95
             array_push($buttons, Button::raw('Report')
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
         Fields\Text::make('email')->label('Email'),
120
         Fields\Text::make('email')->label('Email'),
109
         Fields\Text::make('telefono')->label('Telefono'),
121
         Fields\Text::make('telefono')->label('Telefono'),
110
         Fields\Select2::make('evento_id')->label('Evento')
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
         ->default(isset($this->evento_id) ? $this->evento_id : ''),
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
         Fields\Select2::make('stato')->label('Stato')->options(Prenotazione::getStati()->pluck('value', 'label'))->default(Prenotazione::STATO_INVIATA) ,
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
         Fields\Text::make('note')->label('Note'),
128
         Fields\Text::make('note')->label('Note'),
116
         Fields\Text::make('codice')->label('Codice'),
129
         Fields\Text::make('codice')->label('Codice'),
117
         Fields\Text::make('stato_pagamento')->label('Stato pagamento'),
130
         Fields\Text::make('stato_pagamento')->label('Stato pagamento'),
150
         return [
163
         return [
151
             Column::make('id')->title('ID')->width('10%')->visible(false)->responsivePriority(1)->width('10%'),
164
             Column::make('id')->title('ID')->width('10%')->visible(false)->responsivePriority(1)->width('10%'),
152
             Column::make('stato')->data('stato_display')->title('Stato')->searchable(true)->filter(true)->responsivePriority(1),
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
             Column::make('codice')->title('Codice')->responsivePriority(1),
167
             Column::make('codice')->title('Codice')->responsivePriority(1),
154
             Column::make('cognome')->title('Cognome')->responsivePriority(2),
168
             Column::make('cognome')->title('Cognome')->responsivePriority(2),
155
             Column::make('nome')->title('Nome'),
169
             Column::make('nome')->title('Nome'),
156
             Column::make('email')->title('Email'),
170
             Column::make('email')->title('Email'),
157
             Column::make('telefono')->title('Telefono'),
171
             Column::make('telefono')->title('Telefono'),
158
             Column::make('evento_id_display')->title('Evento'),
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
             Column::computed('action')
175
             Column::computed('action')
162
                   ->title('')
176
                   ->title('')
163
                   ->exportable(false)
177
                   ->exportable(false)

+ 47
- 14
app/DataTables/PrenotazioneDataTableEditor.php 파일 보기

2
 
2
 
3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
+use App\Models\Cucina;
6
+use App\Models\Evento;
5
 use App\Models\Prenotazione;
7
 use App\Models\Prenotazione;
8
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
9
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class PrenotazioneDataTableEditor extends DataTablesEditor
12
 class PrenotazioneDataTableEditor extends DataTablesEditor
15
 {
13
 {
16
   protected $model = Prenotazione::class;
14
   protected $model = Prenotazione::class;
17
-  // protected $uploadDir = '';
18
-  // protected $disk = 'modelliRicevute';
19
 
15
 
20
   protected $messages = [
16
   protected $messages = [
21
     'nome.required' => 'Il nome è richiesto',
17
     'nome.required' => 'Il nome è richiesto',
24
     'telefono.required' => 'Il telefono è richiesto',
20
     'telefono.required' => 'Il telefono è richiesto',
25
     'evento_id.required' => 'L\'evento è richiesto',
21
     'evento_id.required' => 'L\'evento è richiesto',
26
     'cucina_id.required' => 'La cucina è richiesta',
22
     'cucina_id.required' => 'La cucina è richiesta',
27
-    'stato.required' => 'Il stato è richiesto',
23
+    'stato.required' => 'Lo stato è richiesto',
28
     'note.required' => 'La note è richiesta',
24
     'note.required' => 'La note è richiesta',
29
   ];
25
   ];
30
 
26
 
41
       'email' => 'nullable|email',
37
       'email' => 'nullable|email',
42
       'telefono' => 'nullable',
38
       'telefono' => 'nullable',
43
       'evento_id' => 'required|exists:evento,id',
39
       'evento_id' => 'required|exists:evento,id',
44
-      'cucina_id' => 'required|exists:cucina,id',
40
+      'cucina_id' => 'nullable|exists:cucina,id',
45
       'stato' => 'nullable|string',
41
       'stato' => 'nullable|string',
42
+      'confermata' => 'nullable|boolean',
46
       'note' => 'nullable',
43
       'note' => 'nullable',
47
       'codice' => 'required|unique:prenotazione,codice',
44
       'codice' => 'required|unique:prenotazione,codice',
48
       'stato_pagamento' => 'nullable|string',
45
       'stato_pagamento' => 'nullable|string',
68
       'email' => 'nullable|email',
65
       'email' => 'nullable|email',
69
       'telefono' => 'nullable',
66
       'telefono' => 'nullable',
70
       'evento_id' => 'required|exists:evento,id',
67
       'evento_id' => 'required|exists:evento,id',
71
-      'cucina_id' => 'required|exists:cucina,id',
68
+      'cucina_id' => 'nullable|exists:cucina,id',
72
       'stato' => 'nullable|string',
69
       'stato' => 'nullable|string',
70
+      'confermata' => 'nullable|boolean',
73
       'note' => 'nullable',
71
       'note' => 'nullable',
74
-      'codice' => 'required|unique:prenotazione,codice',
72
+      'codice' => 'required|unique:prenotazione,codice,'.$model->getKey(),
75
     ];
73
     ];
76
   }
74
   }
77
 
75
 
92
 
90
 
93
   public function creating(Model $model, array $data): array
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
     return $data;
96
     return $data;
97
   }
97
   }
98
 
98
 
99
   public function updating(Model $model, array $data): array
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
     return $data;
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
   public function messages(): array
138
   public function messages(): array
106
   {
139
   {
107
     return $this->messages;
140
     return $this->messages;

+ 30
- 8
app/DataTables/PrenotazioneTavoloDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\PrenotazioneTavolo;
5
 use App\Models\PrenotazioneTavolo;
6
+use App\Models\Tavolo;
7
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
8
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class PrenotazioneTavoloDataTableEditor extends DataTablesEditor
12
 class PrenotazioneTavoloDataTableEditor extends DataTablesEditor
15
 {
13
 {
90
 
88
 
91
   public function creating(Model $model, array $data): array
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
     return $data;
95
     return $data;
95
   }
96
   }
96
 
97
 
97
   public function updating(Model $model, array $data): array
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
     return $data;
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
   public function messages(): array
125
   public function messages(): array
104
   {
126
   {
105
     return $this->messages;
127
     return $this->messages;

+ 9
- 6
app/DataTables/PrimaNotaDataTable.php 파일 보기

118
      */
118
      */
119
     public function query(PrimaNota $model): QueryBuilder
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
             return $model->newQuery()->whereRaw('1 = 0');
123
             return $model->newQuery()->whereRaw('1 = 0');
123
         }
124
         }
124
 
125
 
125
         return $model->newQuery()
126
         return $model->newQuery()
126
-            ->where('attivita_id', $this->attivita_id)
127
+            ->with('pagamento')
128
+            ->where('attivita_id', $attivitaId)
127
             ->conFiltriIndice()
129
             ->conFiltriIndice()
128
             ->orderBy('created_at', 'desc');
130
             ->orderBy('created_at', 'desc');
129
     }
131
     }
195
                     ->editor(
197
                     ->editor(
196
                         Editor::make()
198
                         Editor::make()
197
                             ->fields([
199
                             ->fields([
198
-                                Fields\Hidden::make('attivita_id')->default($this->attivita_id),
200
+                                Fields\Hidden::make('attivita_id')->default((int) $this->attivita_id),
199
                                 Fields\Select2::make('tipo_movimento')->label('Tipo movimento')->options(PrimaNota::getTipiMovimento()->pluck('value', 'label')),
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
                                 Fields\Text::make('importo')->label('Importo'),
204
                                 Fields\Text::make('importo')->label('Importo'),
202
                                 Fields\Text::make('causale')->label('Causale'),
205
                                 Fields\Text::make('causale')->label('Causale'),
203
                                 Fields\Text::make('riferimento')->label('Riferimento'),
206
                                 Fields\Text::make('riferimento')->label('Riferimento'),
204
                                 Fields\Select2::make('evento_id')
207
                                 Fields\Select2::make('evento_id')
205
                                 ->label('Evento')
208
                                 ->label('Evento')
206
                                 ->options(
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
                                 Fields\Select2::make('fornitore_id')
212
                                 Fields\Select2::make('fornitore_id')
210
                                 ->label('Fornitore')
213
                                 ->label('Fornitore')
211
                                 ->options(
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
                                 // Fields\Checkbox::make('tipo_movimento')->label('Tipo movimento')->options(PrimaNota::getTipiMovimento()->pluck('value', 'label')),
218
                                 // Fields\Checkbox::make('tipo_movimento')->label('Tipo movimento')->options(PrimaNota::getTipiMovimento()->pluck('value', 'label')),

+ 56
- 20
app/DataTables/PrimaNotaDataTableEditor.php 파일 보기

2
 
2
 
3
 namespace App\DataTables;
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
 use App\Models\PrimaNota;
11
 use App\Models\PrimaNota;
12
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
13
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class PrimaNotaDataTableEditor extends DataTablesEditor
17
 class PrimaNotaDataTableEditor extends DataTablesEditor
15
 {
18
 {
16
   protected $model = PrimaNota::class;
19
   protected $model = PrimaNota::class;
17
-  // protected $uploadDir = '';
18
-  // protected $disk = 'modelliRicevute';
19
 
20
 
20
   protected $messages = [
21
   protected $messages = [
21
     'riferimento.required' => 'Il riferimento è richiesto',
22
     'riferimento.required' => 'Il riferimento è richiesto',
23
     'importo.required' => 'L\'importo è richiesto',
24
     'importo.required' => 'L\'importo è richiesto',
24
     'tipo_movimento.required' => 'Il tipo movimento è richiesto',
25
     'tipo_movimento.required' => 'Il tipo movimento è richiesto',
25
     'causale.required' => 'La causale è richiesta',
26
     'causale.required' => 'La causale è richiesta',
26
-    'stato.required' => 'Il stato è richiesto',
27
+    'stato.required' => 'Lo stato è richiesto',
27
     'categoria_contabile_id.required' => 'La categoria contabile è richiesta',
28
     'categoria_contabile_id.required' => 'La categoria contabile è richiesta',
28
   ];
29
   ];
29
 
30
 
35
   public function createRules(): array
36
   public function createRules(): array
36
   {
37
   {
37
     return [
38
     return [
38
-      'attivita_id' => 'required|exists:attivita,id',
39
       'pagamento_id' => 'nullable|exists:pagamento,id',
39
       'pagamento_id' => 'nullable|exists:pagamento,id',
40
       'ordine_id' => 'nullable|exists:ordine,id',
40
       'ordine_id' => 'nullable|exists:ordine,id',
41
       'prenotazione_id' => 'nullable|exists:prenotazione,id',
41
       'prenotazione_id' => 'nullable|exists:prenotazione,id',
43
       'fornitore_id' => 'nullable|exists:fornitore,id',
43
       'fornitore_id' => 'nullable|exists:fornitore,id',
44
       'riferimento' => 'nullable|string',
44
       'riferimento' => 'nullable|string',
45
       'importo' => 'required|numeric',
45
       'importo' => 'required|numeric',
46
-      'tipo_movimento' => 'required|string',   
46
+      'tipo_movimento' => 'required|string',
47
       'causale' => 'required|string',
47
       'causale' => 'required|string',
48
       'categoria_contabile_id' => 'required|exists:categoria_contabile,id',
48
       'categoria_contabile_id' => 'required|exists:categoria_contabile,id',
49
-      // 'stato' => 'nullable|string',
50
-      // 'note' => 'nullable|string',
51
-      // 'codice' => 'nullable|string',
52
       'stato_pagamento' => 'nullable|string',
49
       'stato_pagamento' => 'nullable|string',
53
       'metodo_pagamento' => 'nullable|string',
50
       'metodo_pagamento' => 'nullable|string',
54
     ];
51
     ];
67
   public function editRules(Model $model): array
64
   public function editRules(Model $model): array
68
   {
65
   {
69
     return [
66
     return [
70
-      'attivita_id' => 'required|exists:attivita,id',
71
       'pagamento_id' => 'nullable|exists:pagamento,id',
67
       'pagamento_id' => 'nullable|exists:pagamento,id',
72
       'ordine_id' => 'nullable|exists:ordine,id',
68
       'ordine_id' => 'nullable|exists:ordine,id',
73
       'prenotazione_id' => 'nullable|exists:prenotazione,id',
69
       'prenotazione_id' => 'nullable|exists:prenotazione,id',
75
       'fornitore_id' => 'nullable|exists:fornitore,id',
71
       'fornitore_id' => 'nullable|exists:fornitore,id',
76
       'riferimento' => 'nullable|string',
72
       'riferimento' => 'nullable|string',
77
       'importo' => 'required|numeric',
73
       'importo' => 'required|numeric',
78
-      'tipo_movimento' => 'required|string',   
74
+      'tipo_movimento' => 'required|string',
79
       'causale' => 'required|string',
75
       'causale' => 'required|string',
80
       'stato' => 'nullable|string',
76
       'stato' => 'nullable|string',
81
       'categoria_contabile_id' => 'required|exists:categoria_contabile,id',
77
       'categoria_contabile_id' => 'required|exists:categoria_contabile,id',
82
-      // 'note' => 'nullable|string',
83
-      // 'codice' => 'nullable|string',
84
       'stato_pagamento' => 'nullable|string',
78
       'stato_pagamento' => 'nullable|string',
85
       'metodo_pagamento' => 'nullable|string',
79
       'metodo_pagamento' => 'nullable|string',
86
     ];
80
     ];
103
 
97
 
104
   public function creating(Model $model, array $data): array
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
     return $data;
104
     return $data;
108
   }
105
   }
109
 
106
 
110
   public function updating(Model $model, array $data): array
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
     return $data;
120
     return $data;
115
   }
121
   }
122
+
116
   public function messages(): array
123
   public function messages(): array
117
   {
124
   {
118
     return $this->messages;
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
      */
67
      */
68
     public function query(PrintJob $model): QueryBuilder
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
 
17
 
18
 class PuntoOperatoreDataTable extends DataTable
18
 class PuntoOperatoreDataTable extends DataTable
19
 {
19
 {
20
+    public ?int $attivita_id = null;
21
+
20
     public function __construct()
22
     public function __construct()
21
     {
23
     {
22
         $this->dataTableVariable = 'dataTable_punto_operatore';
24
         $this->dataTableVariable = 'dataTable_punto_operatore';
45
      */
47
      */
46
     public function query(Dispositivo $model): QueryBuilder
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
         return $model->newQuery()
55
         return $model->newQuery()
49
         ->where('tipo', Dispositivo::OPERATORE)
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
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Dispositivo;
5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
8
+use Illuminate\Support\Facades\Session;
7
 use Yajra\DataTables\DataTablesEditor;
9
 use Yajra\DataTables\DataTablesEditor;
8
-use Auth;
9
 
10
 
10
 class PuntoOperatoreDataTableEditor extends DataTablesEditor
11
 class PuntoOperatoreDataTableEditor extends DataTablesEditor
11
 {
12
 {
33
   {
34
   {
34
     return [
35
     return [
35
       'nome'  => 'required',
36
       'nome'  => 'required',
36
-      'attivita_id' => 'required|exists:attivita,id',
37
-      'tipo' => 'required',
37
+      'tipo' => 'required|in:'.Dispositivo::OPERATORE,
38
       'licenza' => 'nullable',
38
       'licenza' => 'nullable',
39
       'url_stampante' => 'nullable',
39
       'url_stampante' => 'nullable',
40
       'ubicazione' => 'nullable',
40
       'ubicazione' => 'nullable',
60
   {
60
   {
61
     return [
61
     return [
62
       'nome'  => 'required',
62
       'nome'  => 'required',
63
-      'attivita_id' => 'required|exists:attivita,id',
64
-      'tipo' => 'required',
63
+      'tipo' => 'required|in:'.Dispositivo::OPERATORE,
65
       'licenza' => 'nullable',
64
       'licenza' => 'nullable',
66
       'url_stampante' => 'nullable',
65
       'url_stampante' => 'nullable',
67
       'ubicazione' => 'nullable',
66
       'ubicazione' => 'nullable',
90
 
89
 
91
   public function creating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
95
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
96
     return $data;
96
     return $data;
97
   }
97
   }
98
 
98
 
99
   public function updating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
104
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
102
     return $data;
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
   public function saved(Model $model, array $data): Model
115
   public function saved(Model $model, array $data): Model
106
   {
116
   {
107
     return $model;
117
     return $model;

+ 8
- 1
app/DataTables/PuntoVenditaDataTable.php 파일 보기

16
 
16
 
17
 class PuntoVenditaDataTable extends DataTable
17
 class PuntoVenditaDataTable extends DataTable
18
 {
18
 {
19
+    public ?int $attivita_id = null;
20
+
19
     public function __construct()
21
     public function __construct()
20
     {
22
     {
21
         $this->dataTableVariable = 'dataTable_punto_vendita';
23
         $this->dataTableVariable = 'dataTable_punto_vendita';
83
      */
85
      */
84
     public function query(Dispositivo $model): QueryBuilder
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
         return $model->newQuery()
93
         return $model->newQuery()
87
         ->whereIn('tipo', [Dispositivo::KIOSK, Dispositivo::CASSA , Dispositivo::CAMERIERE])
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
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Dispositivo;
5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class PuntoVenditaDataTableEditor extends DataTablesEditor
11
 class PuntoVenditaDataTableEditor extends DataTablesEditor
15
 {
12
 {
49
   {
46
   {
50
     return [
47
     return [
51
       'nome'  => 'required',
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
       'licenza' => 'nullable',
50
       'licenza' => 'nullable',
55
       'url_stampante' => 'nullable',
51
       'url_stampante' => 'nullable',
56
       'ubicazione' => 'nullable',
52
       'ubicazione' => 'nullable',
76
   {
72
   {
77
     return [
73
     return [
78
       'nome'  => 'required',
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
       'licenza' => 'nullable',
76
       'licenza' => 'nullable',
82
       'url_stampante' => 'nullable',
77
       'url_stampante' => 'nullable',
83
       'ubicazione' => 'nullable',
78
       'ubicazione' => 'nullable',
106
 
101
 
107
   public function creating(Model $model, array $data): array
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
     return $data;
107
     return $data;
112
   }
108
   }
113
 
109
 
114
   public function updating(Model $model, array $data): array
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
     return $data;
122
     return $data;
120
   }
123
   }
121
   public function messages(): array
124
   public function messages(): array

+ 70
- 39
app/DataTables/RigaFatturazioneDataTable.php 파일 보기

28
     {
28
     {
29
         return (new EloquentDataTable($query))
29
         return (new EloquentDataTable($query))
30
             ->addColumn('action', function ($entity) {
30
             ->addColumn('action', function ($entity) {
31
-                return view('fatturazione.menu',['entity' => $entity]);
31
+                return view('fatturazione.menu', ['entity' => $entity]);
32
             })
32
             })
33
             ->addColumn('attivita_id', function ($entity) {
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
             ->addColumn('dispositivo_id', function ($entity) {
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
             ->addColumn('prezzo', function ($entity) {
49
             ->addColumn('prezzo', function ($entity) {
40
                 return number_format($entity->prezzo, 2, ',', '.') . ' €';
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
             ->addColumn('stato_display', function ($entity) {
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
             ->addColumn('listino_prezzi_display', function ($entity) {
62
             ->addColumn('listino_prezzi_display', function ($entity) {
46
                 return optional($entity->listinoPrezzi)->label;
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
             ->setRowId('id');
79
             ->setRowId('id');
50
     }
80
     }
51
 
81
 
56
      */
86
      */
57
     public function query(RigaFatturazione $model): QueryBuilder
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
             $query->whereIn('stato', [RigaFatturazione::GRATUITO, RigaFatturazione::REGISTRATO]);
94
             $query->whereIn('stato', [RigaFatturazione::GRATUITO, RigaFatturazione::REGISTRATO]);
63
         }
95
         }
64
-        if($this->superadmin){
96
+
97
+        if ($this->superadmin) {
65
             return $query;
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
      */
180
      */
150
     public function getColumns(): array
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
         return $columns;
208
         return $columns;
178
     }
209
     }
179
 
210
 

+ 34
- 36
app/DataTables/RigaFatturazioneDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\RigaFatturazione;
5
 use App\Models\RigaFatturazione;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
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
 use Illuminate\Validation\ValidationException;
10
 use Illuminate\Validation\ValidationException;
11
-use Storage;
12
-use Illuminate\Support\Str;
11
+use Yajra\DataTables\DataTablesEditor;
13
 
12
 
14
 class RigaFatturazioneDataTableEditor extends DataTablesEditor
13
 class RigaFatturazioneDataTableEditor extends DataTablesEditor
15
 {
14
 {
16
   protected $model = RigaFatturazione::class;
15
   protected $model = RigaFatturazione::class;
17
-  // protected $uploadDir = '';
18
-  // protected $disk = 'modelliRicevute';
19
 
16
 
20
   protected $messages = [
17
   protected $messages = [
21
     'attivita_id.required' => 'L\'attività è richiesta',
18
     'attivita_id.required' => 'L\'attività è richiesta',
25
     'listino_prezzi_id.required' => 'Il listino prezzi è richiesto',
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
   public function createRules(): array
25
   public function createRules(): array
34
   {
26
   {
35
     return [
27
     return [
36
-      'attivita_id'  => 'required',
37
       'qta' => 'required',
28
       'qta' => 'required',
38
-      // 'prezzo' => 'required',
39
-      // 'tipo' => 'required',
40
       'listino_prezzi_id' => 'required',
29
       'listino_prezzi_id' => 'required',
41
     ];
30
     ];
42
   }
31
   }
43
 
32
 
44
-  public function createMessages(): array{
33
+  public function createMessages(): array
34
+  {
45
     return $this->messages;
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
   public function editRules(Model $model): array
38
   public function editRules(Model $model): array
55
   {
39
   {
56
     return [
40
     return [
57
-      'attivita_id'  => 'required',
58
       'qta' => 'required',
41
       'qta' => 'required',
59
-      // 'prezzo' => 'required',
60
-      // 'tipo' => 'required',
61
       'listino_prezzi_id' => 'required',
42
       'listino_prezzi_id' => 'required',
62
     ];
43
     ];
63
   }
44
   }
64
 
45
 
65
-  public function editMessages(): array{
46
+  public function editMessages(): array
47
+  {
66
     return $this->messages;
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
   public function removeRules(Model $model): array
51
   public function removeRules(Model $model): array
76
   {
52
   {
77
     return [];
53
     return [];
79
 
55
 
80
   public function creating(Model $model, array $data): array
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
     $data['prezzo'] = $listinoPrezzi->prezzo;
62
     $data['prezzo'] = $listinoPrezzi->prezzo;
85
     $data['tipo'] = $listinoPrezzi->categoria;
63
     $data['tipo'] = $listinoPrezzi->categoria;
64
+
86
     return $data;
65
     return $data;
87
   }
66
   }
88
 
67
 
89
   public function updating(Model $model, array $data): array
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
     return $data;
82
     return $data;
94
   }
83
   }
84
+
95
   public function messages(): array
85
   public function messages(): array
96
   {
86
   {
97
     return $this->messages;
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
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Dispositivo;
5
 use App\Models\Dispositivo;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class StampanteDataTableEditor extends DataTablesEditor
11
 class StampanteDataTableEditor extends DataTablesEditor
15
 {
12
 {
49
   {
46
   {
50
     return [
47
     return [
51
       'nome'  => 'required',
48
       'nome'  => 'required',
52
-      'tipo' => 'required',
53
-      'attivita_id' => 'required|exists:attivita,id',
49
+      'tipo' => 'required|in:'.Dispositivo::STAMPANTE,
54
       'licenza' => 'nullable',
50
       'licenza' => 'nullable',
55
       'url_stampante' => 'nullable',
51
       'url_stampante' => 'nullable',
56
       'ubicazione' => 'nullable',
52
       'ubicazione' => 'nullable',
76
   {
72
   {
77
     return [
73
     return [
78
       'nome'  => 'required',
74
       'nome'  => 'required',
79
-      'tipo' => 'required',
80
-      'attivita_id' => 'required|exists:attivita,id',
75
+      'tipo' => 'required|in:'.Dispositivo::STAMPANTE,
81
       'licenza' => 'nullable',
76
       'licenza' => 'nullable',
82
       'url_stampante' => 'nullable',
77
       'url_stampante' => 'nullable',
83
       'ubicazione' => 'nullable',
78
       'ubicazione' => 'nullable',
106
 
101
 
107
   public function creating(Model $model, array $data): array
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
     return $data;
108
     return $data;
112
   }
109
   }
113
 
110
 
114
   public function updating(Model $model, array $data): array
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
     return $data;
124
     return $data;
120
   }
125
   }
121
   public function messages(): array
126
   public function messages(): array

+ 7
- 4
app/DataTables/TavoloDataTable.php 파일 보기

15
 
15
 
16
 class TavoloDataTable extends DataTable
16
 class TavoloDataTable extends DataTable
17
 {
17
 {
18
+    public ?int $attivita_id = null;
19
+
18
     public function __construct(){
20
     public function __construct(){
19
         $this->dataTableVariable = 'dataTable_tavolo';
21
         $this->dataTableVariable = 'dataTable_tavolo';
20
     }
22
     }
42
      */
44
      */
43
     public function query(Tavolo $model): QueryBuilder
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
             return $model->newQuery()->whereRaw('1 = 0');
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
                     ->editor(
84
                     ->editor(
82
                         Editor::make()
85
                         Editor::make()
83
                             ->fields([
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
                                 Fields\Text::make('label')->label('Label'),
88
                                 Fields\Text::make('label')->label('Label'),
86
                                 Fields\Text::make('posti')->label('Posti'),
89
                                 Fields\Text::make('posti')->label('Posti'),
87
                                 Fields\Text::make('ubicazione')->label('Ubicazione'),
90
                                 Fields\Text::make('ubicazione')->label('Ubicazione'),

+ 13
- 10
app/DataTables/TavoloDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Tavolo;
5
 use App\Models\Tavolo;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class TavoloDataTableEditor extends DataTablesEditor
11
 class TavoloDataTableEditor extends DataTablesEditor
15
 {
12
 {
33
   {
30
   {
34
     return [
31
     return [
35
       'label'  => 'required',
32
       'label'  => 'required',
36
-      'attivita_id' => 'required|exists:attivita,id',
37
       'posti' => 'nullable|numeric|min:0',
33
       'posti' => 'nullable|numeric|min:0',
38
       'ubicazione' => 'nullable',
34
       'ubicazione' => 'nullable',
39
       'is_attivo' => 'boolean',
35
       'is_attivo' => 'boolean',
54
   {
50
   {
55
     return [
51
     return [
56
       'label'  => 'required',
52
       'label'  => 'required',
57
-      'attivita_id' => 'required|exists:attivita,id',
58
       'posti' => 'nullable|numeric|min:0',
53
       'posti' => 'nullable|numeric|min:0',
59
       'ubicazione' => 'nullable',
54
       'ubicazione' => 'nullable',
60
       'is_attivo' => 'boolean',
55
       'is_attivo' => 'boolean',
78
 
73
 
79
   public function creating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
78
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
83
     return $data;
79
     return $data;
84
   }
80
   }
85
 
81
 
86
   public function updating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
86
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
91
     return $data;
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
   public function messages(): array
96
   public function messages(): array
94
   {
97
   {
95
     return $this->messages;
98
     return $this->messages;

+ 13
- 10
app/DataTables/TestiDataTableEditor.php 파일 보기

3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
 use App\Models\Testi;
5
 use App\Models\Testi;
6
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
7
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
+use Illuminate\Support\Facades\Session;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class TestiDataTableEditor extends DataTablesEditor
11
 class TestiDataTableEditor extends DataTablesEditor
15
 {
12
 {
35
   {
32
   {
36
     return [
33
     return [
37
       'titolo'  => 'required',
34
       'titolo'  => 'required',
38
-      'attivita_id' => 'required|exists:attivita,id',
39
       'descrizione' => 'nullable',
35
       'descrizione' => 'nullable',
40
       'testo' => 'nullable',
36
       'testo' => 'nullable',
41
       'ambiente' => 'nullable',
37
       'ambiente' => 'nullable',
58
   {
54
   {
59
     return [
55
     return [
60
       'titolo'  => 'required',
56
       'titolo'  => 'required',
61
-      'attivita_id' => 'required|exists:attivita,id',
62
       'descrizione' => 'nullable',
57
       'descrizione' => 'nullable',
63
       'testo' => 'nullable',
58
       'testo' => 'nullable',
64
       'ambiente' => 'nullable',
59
       'ambiente' => 'nullable',
84
 
79
 
85
   public function creating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
84
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
89
     return $data;
85
     return $data;
90
   }
86
   }
91
 
87
 
92
   public function updating(Model $model, array $data): array
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
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
92
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
97
     return $data;
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
   public function messages(): array
102
   public function messages(): array
100
   {
103
   {
101
     return $this->messages;
104
     return $this->messages;

+ 10
- 5
app/DataTables/VariantePiattoDataTable.php 파일 보기

58
      */
58
      */
59
     public function query(VariantePiatto $model): QueryBuilder
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
         if (isset($this->cucina_id)) {
67
         if (isset($this->cucina_id)) {
63
             $query->where('cucina_id', $this->cucina_id);
68
             $query->where('cucina_id', $this->cucina_id);
64
         }
69
         }
92
                     ->editor(Editor::make()
97
                     ->editor(Editor::make()
93
                         ->ajax(route('variante-piatto.store'))
98
                         ->ajax(route('variante-piatto.store'))
94
                         ->fields([
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
                             Fields\Text::make('label')->label('Nome'),
101
                             Fields\Text::make('label')->label('Nome'),
97
                             Fields\Text::make('prezzo')->label('Prezzo'),
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
                     ->language(asset('assets/Italian.json'))
108
                     ->language(asset('assets/Italian.json'))

+ 36
- 9
app/DataTables/VariantePiattoDataTableEditor.php 파일 보기

2
 
2
 
3
 namespace App\DataTables;
3
 namespace App\DataTables;
4
 
4
 
5
+use App\Models\Cucina;
6
+use App\Models\Piatto;
5
 use App\Models\VariantePiatto;
7
 use App\Models\VariantePiatto;
8
+use App\Services\Attivita\AttivitaService;
6
 use Illuminate\Database\Eloquent\Model;
9
 use Illuminate\Database\Eloquent\Model;
7
-use Illuminate\Validation\Rule;
8
 use Yajra\DataTables\DataTablesEditor;
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
 class VariantePiattoDataTableEditor extends DataTablesEditor
13
 class VariantePiattoDataTableEditor extends DataTablesEditor
15
 {
14
 {
38
   {
37
   {
39
     return [
38
     return [
40
       'label'  => 'required',
39
       'label'  => 'required',
41
-      'attivita_id' => 'required|exists:attivita,id',
42
       'prezzo' => 'required',
40
       'prezzo' => 'required',
43
-      'is_attivo' => 'boolean',
44
       'piatto_id' => 'nullable|exists:piatto,id',
41
       'piatto_id' => 'nullable|exists:piatto,id',
45
       'cucina_id' => 'required|exists:cucina,id',
42
       'cucina_id' => 'required|exists:cucina,id',
46
     ];
43
     ];
60
   {
57
   {
61
     return [
58
     return [
62
       'label'  => 'required',
59
       'label'  => 'required',
63
-      'attivita_id' => 'required|exists:attivita,id',
64
       'prezzo' => 'required',
60
       'prezzo' => 'required',
65
-      'is_attivo' => 'boolean',
66
       'piatto_id' => 'nullable|exists:piatto,id',
61
       'piatto_id' => 'nullable|exists:piatto,id',
67
       'cucina_id' => 'required|exists:cucina,id',
62
       'cucina_id' => 'required|exists:cucina,id',
68
     ];
63
     ];
86
 
81
 
87
   public function creating(Model $model, array $data): array
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
     $data['is_attivo'] = array_key_exists('is_attivo', $data)
88
     $data['is_attivo'] = array_key_exists('is_attivo', $data)
90
       ? filter_var($data['is_attivo'], FILTER_VALIDATE_BOOLEAN)
89
       ? filter_var($data['is_attivo'], FILTER_VALIDATE_BOOLEAN)
91
       : true;
90
       : true;
94
 
93
 
95
   public function updating(Model $model, array $data): array
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
     if (array_key_exists('is_attivo', $data)) {
100
     if (array_key_exists('is_attivo', $data)) {
98
       $data['is_attivo'] = filter_var($data['is_attivo'], FILTER_VALIDATE_BOOLEAN);
101
       $data['is_attivo'] = filter_var($data['is_attivo'], FILTER_VALIDATE_BOOLEAN);
99
     }
102
     }
100
     return $data;
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
   public function messages(): array
129
   public function messages(): array
103
   {
130
   {
104
     return $this->messages;
131
     return $this->messages;

+ 2
- 0
app/Http/Controllers/AllergeneController.php 파일 보기

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

+ 13
- 0
app/Http/Controllers/AsportoController.php 파일 보기

3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
 use Illuminate\Http\Request;
5
 use Illuminate\Http\Request;
6
+use Illuminate\Routing\Controllers\Middleware;
6
 use App\Models\Asporto;
7
 use App\Models\Asporto;
7
 use Illuminate\Support\Collection;
8
 use Illuminate\Support\Collection;
8
 
9
 
14
         'view-asporto' => 'Visualizza asporto',
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
     public function index(Request $request)
30
     public function index(Request $request)
18
     {
31
     {
19
 
32
 

+ 46
- 9
app/Http/Controllers/AttivitaController.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\Attivita;
8
 use App\Models\Attivita;
9
+use App\Models\Evento;
7
 use App\DataTables\AttivitaDataTable;
10
 use App\DataTables\AttivitaDataTable;
8
 use App\DataTables\AttivitaDataTableEditor;
11
 use App\DataTables\AttivitaDataTableEditor;
9
 use Illuminate\Support\Facades\Auth;
12
 use Illuminate\Support\Facades\Auth;
24
     public static function middleware(): array
27
     public static function middleware(): array
25
     {
28
     {
26
         return [
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
             new Middleware('permission:create-attivita|edit-attivita|delete-attivita', only: ['store', 'update', 'destroy']),
32
             new Middleware('permission:create-attivita|edit-attivita|delete-attivita', only: ['store', 'update', 'destroy']),
29
         ];
33
         ];
30
     }
34
     }
57
 
61
 
58
     public function show($attivita_id)
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
             'dispositivi',
74
             'dispositivi',
62
             'eventi',
75
             'eventi',
63
             'prenotazioni',
76
             'prenotazioni',
64
             'piatti',
77
             'piatti',
65
             'fornitori',
78
             'fornitori',
66
-        ])->find($attivita_id);
79
+        ]);
67
 
80
 
68
         return view('attivita.show', ['attivita' => $attivita]);
81
         return view('attivita.show', ['attivita' => $attivita]);
69
     }
82
     }
71
     public function select(Request $request)
84
     public function select(Request $request)
72
     {
85
     {
73
         $request->validate([
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
         return redirect()->route('dashboard')->with('success', 'Attività selezionata con successo');
105
         return redirect()->route('dashboard')->with('success', 'Attività selezionata con successo');
78
     }
106
     }
79
 
107
 
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
             return redirect()->route('welcome')->with('error', 'Attività non trovata');
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
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\Bacheca;
8
 use App\Models\Bacheca;
7
 use App\DataTables\BachecaDataTable;
9
 use App\DataTables\BachecaDataTable;
9
 use Illuminate\Support\Facades\Auth;
11
 use Illuminate\Support\Facades\Auth;
10
 use App\DataTables\ContenutoBachecaDataTable;
12
 use App\DataTables\ContenutoBachecaDataTable;
11
 use Illuminate\Support\Facades\Session;
13
 use Illuminate\Support\Facades\Session;
14
+use App\Services\Attivita\AttivitaService;
12
 
15
 
13
 class BachecaController extends Controller
16
 class BachecaController extends Controller
14
 {
17
 {
23
     public static function middleware(): array
26
     public static function middleware(): array
24
     {
27
     {
25
         return [
28
         return [
26
-            new Middleware('permission:view-bacheca', only: ['index']),
29
+            new Middleware('permission:view-bacheca', only: ['index', 'show']),
27
             new Middleware('permission:create-bacheca|edit-bacheca|delete-bacheca', only: ['store', 'update', 'destroy']),
30
             new Middleware('permission:create-bacheca|edit-bacheca|delete-bacheca', only: ['store', 'update', 'destroy']),
28
         ];
31
         ];
29
     }
32
     }
57
     public function show(ContenutoBachecaDataTable $datatable, Request $request)
60
     public function show(ContenutoBachecaDataTable $datatable, Request $request)
58
     {
61
     {
59
         $bacheca = Bacheca::find($request->get('bacheca_id'));
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
         $datatable->bacheca_id = $bacheca->id;
68
         $datatable->bacheca_id = $bacheca->id;
61
         return $datatable->render('bacheca.show', ['bacheca' => $bacheca]);
69
         return $datatable->render('bacheca.show', ['bacheca' => $bacheca]);
62
     }
70
     }

+ 14
- 4
app/Http/Controllers/BachecaHasContenutoController.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\BachecaHasContenuto;
8
 use App\Models\BachecaHasContenuto;
7
 use App\Models\Bacheca;
9
 use App\Models\Bacheca;
8
 use App\Models\ContenutoBacheca;
10
 use App\Models\ContenutoBacheca;
9
 use Illuminate\Support\Facades\Auth;
11
 use Illuminate\Support\Facades\Auth;
10
 use Illuminate\Support\Facades\Session;
12
 use Illuminate\Support\Facades\Session;
13
+use App\Services\Attivita\AttivitaService;
11
 
14
 
12
 class BachecaHasContenutoController extends Controller
15
 class BachecaHasContenutoController extends Controller
13
 {
16
 {
22
     public static function middleware(): array
25
     public static function middleware(): array
23
     {
26
     {
24
         return [
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
 
37
 
35
     public function associa_contenuto(Request $request)
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
         return view('contenuto_bacheca.associa_contenuto', ['contenuti' => $contenuti]);
43
         return view('contenuto_bacheca.associa_contenuto', ['contenuti' => $contenuti]);
39
     }
44
     }
40
 
45
 
47
         
52
         
48
         $bacheca = Bacheca::find($request->bacheca_id);
53
         $bacheca = Bacheca::find($request->bacheca_id);
49
         $contenuto = ContenutoBacheca::find($request->contenuto_id);
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
         $bacheca->contenuti()->attach($contenuto);
61
         $bacheca->contenuti()->attach($contenuto);
52
         
62
         
53
         return response()->json(['message' => 'Contenuto associato con successo']);
63
         return response()->json(['message' => 'Contenuto associato con successo']);

+ 15
- 4
app/Http/Controllers/BilancioController.php 파일 보기

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

+ 114
- 72
app/Http/Controllers/CarrelloController.php 파일 보기

3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
 use Illuminate\Http\Request;
5
 use Illuminate\Http\Request;
6
+use Illuminate\Routing\Controllers\Middleware;
6
 use App\Models\Ordine;
7
 use App\Models\Ordine;
7
-use App\Models\PuntoVendita;
8
+// use App\Models\PuntoVendita;
8
 use App\Models\Attivita;
9
 use App\Models\Attivita;
9
 use App\Models\Dispositivo;
10
 use App\Models\Dispositivo;
10
 use App\Models\Pagamento;
11
 use App\Models\Pagamento;
16
 use Illuminate\Support\Facades\Session;
17
 use Illuminate\Support\Facades\Session;
17
 use App\Http\Controllers\PagamentoController;
18
 use App\Http\Controllers\PagamentoController;
18
 use App\Services\Carrello\CarrelloService;
19
 use App\Services\Carrello\CarrelloService;
20
+use App\Services\Attivita\AttivitaService;
19
 
21
 
20
 class CarrelloController extends Controller
22
 class CarrelloController extends Controller
21
 {
23
 {
22
-
23
     private CarrelloService $carrelloService;
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
     public function __construct(CarrelloService $carrelloService)
37
     public function __construct(CarrelloService $carrelloService)
26
     {
38
     {
27
         $this->carrelloService = $carrelloService;
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
         $ordine = Ordine::where([
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
         ])->orderBy('created_at', 'desc')->first();
59
         ])->orderBy('created_at', 'desc')->first();
42
-    // dd($ordine->count());
60
+
43
         return $dataTable->render('punto_vendita.cassa._partials.carrello.index', ['ordine' => $ordine]);
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
         $request->validate([
66
         $request->validate([
49
             'ordine_id' => 'nullable|integer',
67
             'ordine_id' => 'nullable|integer',
50
             'piatto_id' => 'required|integer|exists:piatto,id',
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
             'riga_ordine_id' => 'nullable|integer|exists:riga_ordine,id',
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
         // Tolleranza su ordine_id stale: se non e` valido, usa/crea il carrello corrente per dispositivo+attivita.
88
         // Tolleranza su ordine_id stale: se non e` valido, usa/crea il carrello corrente per dispositivo+attivita.
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
             return response()->json([
304
             return response()->json([
285
                 'success' => true,
305
                 'success' => true,
286
                 'message' => 'Totale carrello',
306
                 'message' => 'Totale carrello',
289
                 'quantita_totale' => 0,
309
                 'quantita_totale' => 0,
290
             ]);
310
             ]);
291
         }
311
         }
312
+
313
+        $ordine = $this->carrelloService->carrelloDiQuestaCassa((int) $request->ordine_id);
292
         // dd([$ordine->prezzo , $request->all()]);
314
         // dd([$ordine->prezzo , $request->all()]);
293
         if($ordine->prezzo == null || $ordine->prezzo == 0){
315
         if($ordine->prezzo == null || $ordine->prezzo == 0){
294
             if($ordine->righe_ordine->count() >0){
316
             if($ordine->righe_ordine->count() >0){
310
             'quantita_totale' => $quantitaTotale,
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
         $info = is_array($ordine->info) ? $ordine->info : [];
341
         $info = is_array($ordine->info) ? $ordine->info : [];
323
         $info['cliente'] = $request->cliente;
342
         $info['cliente'] = $request->cliente;
324
         $info['tavolo'] = $request->tavolo;
343
         $info['tavolo'] = $request->tavolo;
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
         $ordine->prezzo = $ordine->righe_ordine->sum('prezzo');
359
         $ordine->prezzo = $ordine->righe_ordine->sum('prezzo');
355
         // $ordine->stato = Ordine::CHECKOUT;
360
         // $ordine->stato = Ordine::CHECKOUT;
361
     }
366
     }
362
 
367
 
363
     public function paga_ordine(Request $request){
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
         $pagamento = Pagamento::create([
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
             'ordine_id' => $ordine->id,
397
             'ordine_id' => $ordine->id,
381
             'metodo_pagamento_id' => $request->metodo_pagamento_id,
398
             'metodo_pagamento_id' => $request->metodo_pagamento_id,
382
             'tipo' => $request->tipo,
399
             'tipo' => $request->tipo,
406
                     $ordine->update(['stato' => Ordine::PAGATO]);
423
                     $ordine->update(['stato' => Ordine::PAGATO]);
407
                     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);
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
                 }else{
425
                 }else{
426
+                    $pagamento->stato = Pagamento::ERRORE;
427
+                    $pagamento->save();
428
+
409
                     $ordine->stato = Ordine::CARRELLO;
429
                     $ordine->stato = Ordine::CARRELLO;
410
                     $ordine->save();
430
                     $ordine->save();
411
                     return back()->with('error', 'Pagamento con contanti non riuscito. '.$pagamentoResult['message']);
431
                     return back()->with('error', 'Pagamento con contanti non riuscito. '.$pagamentoResult['message']);
417
                 // $pagamento->save();
437
                 // $pagamento->save();
418
                 // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con bonifico riuscito.');
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
                 $ordine->stato = Ordine::CARRELLO;
443
                 $ordine->stato = Ordine::CARRELLO;
421
                     $ordine->save();
444
                     $ordine->save();
422
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
445
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
426
                 // $pagamento->update(['stato' , Pagamento::PAGATO]);
449
                 // $pagamento->update(['stato' , Pagamento::PAGATO]);
427
                 // $pagamento->save();
450
                 // $pagamento->save();
428
                 // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con paypal riuscito.');
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
                 $ordine->stato = Ordine::CARRELLO;
455
                 $ordine->stato = Ordine::CARRELLO;
431
                     $ordine->save();
456
                     $ordine->save();
432
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
457
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
436
                 // $pagamento->update(['stato' , Pagamento::PAGATO]);
461
                 // $pagamento->update(['stato' , Pagamento::PAGATO]);
437
                 // $pagamento->save();
462
                 // $pagamento->save();
438
                 // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con carta di debito riuscito.');
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
                 $ordine->stato = Ordine::CARRELLO;
467
                 $ordine->stato = Ordine::CARRELLO;
441
                     $ordine->save();
468
                     $ordine->save();
442
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
469
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
443
 
470
 
444
                 break;
471
                 break;
445
             case MetodoPagamento::CUPON:
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
                 if($pagamentoResult['result'] === true){
475
                 if($pagamentoResult['result'] === true){
449
                     $ordine->update(['stato' => Ordine::PAGATO]);
476
                     $ordine->update(['stato' => Ordine::PAGATO]);
450
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con cupon riuscito.');
477
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con cupon riuscito.');
451
                 }else{
478
                 }else{
479
+                    $pagamento->stato = Pagamento::ERRORE;
480
+                    $pagamento->save();
481
+
452
                     $ordine->stato = Ordine::CARRELLO;
482
                     $ordine->stato = Ordine::CARRELLO;
453
                     $ordine->save();
483
                     $ordine->save();
454
                     return back()->with('error', 'Pagamento con cupon non riuscito. '.$pagamentoResult['message']);
484
                     return back()->with('error', 'Pagamento con cupon non riuscito. '.$pagamentoResult['message']);
460
                 
490
                 
461
                 if($pagamentoResult['result'] === true){
491
                 if($pagamentoResult['result'] === true){
462
                     $pagamento->update(['stato' => Pagamento::PAGATO]);
492
                     $pagamento->update(['stato' => Pagamento::PAGATO]);
463
-                    $pagamento->save();
493
+                    $ordine->update(['stato' => Ordine::PAGATO]);
494
+
464
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con wallet riuscito.');
495
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con wallet riuscito.');
465
                 }else{
496
                 }else{
466
                     $pagamento->stato = Pagamento::ERRORE;
497
                     $pagamento->stato = Pagamento::ERRORE;
475
                     // $pagamento->update(['stato' , Pagamento::PAGATO]);
506
                     // $pagamento->update(['stato' , Pagamento::PAGATO]);
476
                     // $pagamento->save();
507
                     // $pagamento->save();
477
                     // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con apple pay riuscito.');
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
                     $ordine->stato = Ordine::CARRELLO;
512
                     $ordine->stato = Ordine::CARRELLO;
480
                     $ordine->save();
513
                     $ordine->save();
481
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
514
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
485
                 // $pagamento->update(['stato' , Pagamento::PAGATO]);
518
                 // $pagamento->update(['stato' , Pagamento::PAGATO]);
486
                 // $pagamento->save();
519
                 // $pagamento->save();
487
                 // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con google pay riuscito.');
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
                 $ordine->stato = Ordine::CARRELLO;
524
                 $ordine->stato = Ordine::CARRELLO;
490
                     $ordine->save();
525
                     $ordine->save();
491
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
526
                     return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
498
                     $ordine->update(['stato' => Ordine::PAGATO]);
533
                     $ordine->update(['stato' => Ordine::PAGATO]);
499
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con contanti riuscito. ->'.$pagamento->metodo_pagamento->tipo);
534
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con contanti riuscito. ->'.$pagamento->metodo_pagamento->tipo);
500
                 }else{
535
                 }else{
536
+                    $pagamento->stato = Pagamento::ERRORE;
537
+                    $pagamento->save();
538
+
501
                     $ordine->stato = Ordine::CARRELLO;
539
                     $ordine->stato = Ordine::CARRELLO;
502
                     $ordine->save();
540
                     $ordine->save();
503
                     return back()->with('error', 'Pagamento con contanti non riuscito. '.$pagamentoResult['message']);
541
                     return back()->with('error', 'Pagamento con contanti non riuscito. '.$pagamentoResult['message']);
504
                 }
542
                 }
543
+                break;
505
 
544
 
506
             case MetodoPagamento::STAFF:
545
             case MetodoPagamento::STAFF:
507
                 $pagamentoResult = app('\App\Services\Paga\Staff')->paga($pagamento);
546
                 $pagamentoResult = app('\App\Services\Paga\Staff')->paga($pagamento);
510
                     $ordine->update(['stato' => Ordine::PAGATO]);
549
                     $ordine->update(['stato' => Ordine::PAGATO]);
511
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con staff riuscito.');
550
                     return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con staff riuscito.');
512
                 }else{
551
                 }else{
552
+                    $pagamento->stato = Pagamento::ERRORE;
553
+                    $pagamento->save();
554
+
513
                     $ordine->stato = Ordine::CARRELLO;
555
                     $ordine->stato = Ordine::CARRELLO;
514
                     $ordine->save();
556
                     $ordine->save();
515
                     return back()->with('error', 'Pagamento con staff non riuscito. '.$pagamentoResult['message']);
557
                     return back()->with('error', 'Pagamento con staff non riuscito. '.$pagamentoResult['message']);

+ 2
- 0
app/Http/Controllers/CategoriaContabileController.php 파일 보기

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

+ 3
- 1
app/Http/Controllers/ChiusuraServizioController.php 파일 보기

12
 use Illuminate\Routing\Controllers\Middleware;
12
 use Illuminate\Routing\Controllers\Middleware;
13
 use Illuminate\Support\Facades\Auth;
13
 use Illuminate\Support\Facades\Auth;
14
 use Illuminate\Support\Facades\Session;
14
 use Illuminate\Support\Facades\Session;
15
+use App\Services\Attivita\AttivitaService;
15
 
16
 
16
 class ChiusuraServizioController extends Controller
17
 class ChiusuraServizioController extends Controller
17
 {
18
 {
101
       return redirect()->back()->with('error', 'Non autorizzato');
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
     $attivita = Attivita::find($attivitaId);
107
     $attivita = Attivita::find($attivitaId);
106
     if (!$attivita) {
108
     if (!$attivita) {
107
       return redirect()->back()->with('error', 'Attività non trovata');
109
       return redirect()->back()->with('error', 'Attività non trovata');

+ 380
- 18
app/Http/Controllers/ConsultaController.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+use App\Models\EventoForm;
5
 use App\Models\Ordine;
6
 use App\Models\Ordine;
6
 use App\Models\Prenotazione;
7
 use App\Models\Prenotazione;
8
+use App\Models\PrenotazioneRisposta;
9
+use App\Notifications\PrenotazioneLinkModifica;
10
+use App\Services\Prenotazione\AccessoModificaCliente;
7
 use Endroid\QrCode\Builder\Builder;
11
 use Endroid\QrCode\Builder\Builder;
8
 use Endroid\QrCode\Color\Color;
12
 use Endroid\QrCode\Color\Color;
9
 use Endroid\QrCode\Writer\SvgWriter;
13
 use Endroid\QrCode\Writer\SvgWriter;
10
 use Illuminate\Http\Request;
14
 use Illuminate\Http\Request;
15
+use Illuminate\Support\Facades\Notification;
16
+use Illuminate\Support\Facades\Validator;
11
 
17
 
12
 class ConsultaController extends Controller
18
 class ConsultaController extends Controller
13
 {
19
 {
18
 
24
 
19
     public function scontrino_show(Request $request)
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
             return redirect()->route('consulta.index')->with('error', 'Ordine non trovato');
29
             return redirect()->route('consulta.index')->with('error', 'Ordine non trovato');
25
         }
30
         }
31
+
26
         return view('consulta.scontrino.show', compact('ordine'));
32
         return view('consulta.scontrino.show', compact('ordine'));
27
     }
33
     }
28
-    
34
+
29
     public function comanda_show(Request $request)
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
             return redirect()->route('consulta.index')->with('error', 'Ordine non trovato');
39
             return redirect()->route('consulta.index')->with('error', 'Ordine non trovato');
34
         }
40
         }
41
+
35
         return view('consulta.comanda.show', compact('ordine'));
42
         return view('consulta.comanda.show', compact('ordine'));
36
     }
43
     }
44
+
37
     public function prenotazione_show(Request $request)
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
         $prenotazione = Prenotazione::query()
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
             ->with([
382
             ->with([
41
                 'risposte',
383
                 'risposte',
384
+                'evento.attivita',
42
                 'evento.form' => function ($q) {
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
             ->first();
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
         $qrBuilder = new Builder(
421
         $qrBuilder = new Builder(
53
             writer: new SvgWriter(),
422
             writer: new SvgWriter(),
54
             writerOptions: [
423
             writerOptions: [
56
             ],
425
             ],
57
         );
426
         );
58
 
427
 
59
-        $codiceQrSvg = $qrBuilder->build(
428
+        return $qrBuilder->build(
60
             data: (string) $prenotazione->codice,
429
             data: (string) $prenotazione->codice,
61
             size: 168,
430
             size: 168,
62
             margin: 4,
431
             margin: 4,
63
             foregroundColor: new Color(21, 38, 92),
432
             foregroundColor: new Color(21, 38, 92),
64
-            // class: 'bg-primary',
65
-            // backgroundColor: new Color(245, 130, 32),
66
         )->getString();
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
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\ContenutoBacheca;
8
 use App\Models\ContenutoBacheca;
7
 use App\DataTables\ContenutoBachecaDataTable;
9
 use App\DataTables\ContenutoBachecaDataTable;
8
 use App\DataTables\ContenutoBachecaDataTableEditor;
10
 use App\DataTables\ContenutoBachecaDataTableEditor;
9
 use Illuminate\Support\Facades\Auth;
11
 use Illuminate\Support\Facades\Auth;
10
 use Illuminate\Support\Facades\Session;
12
 use Illuminate\Support\Facades\Session;
13
+use App\Services\Attivita\AttivitaService;
11
 
14
 
12
 class ContenutoBachecaController extends Controller
15
 class ContenutoBachecaController extends Controller
13
 {
16
 {
56
     public function show(Request $request)
59
     public function show(Request $request)
57
     {
60
     {
58
         $contenuto_bacheca = ContenutoBacheca::find($request->get('contenuto_bacheca_id'));
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
         return view('contenuto_bacheca.show', ['contenuto_bacheca' => $contenuto_bacheca]);
66
         return view('contenuto_bacheca.show', ['contenuto_bacheca' => $contenuto_bacheca]);
60
     }
67
     }
61
     
68
     

+ 14
- 3
app/Http/Controllers/Controller.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
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
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\Cucina;
8
 use App\Models\Cucina;
7
 use App\DataTables\CucinaDataTable;
9
 use App\DataTables\CucinaDataTable;
23
     public static function middleware(): array
25
     public static function middleware(): array
24
     {
26
     {
25
         return [
27
         return [
26
-            new Middleware('permission:view-cucina', only: ['index']),
28
+            new Middleware('permission:view-cucina', only: ['index', 'dashboard']),
27
             new Middleware('permission:create-cucina|edit-cucina|delete-cucina', only: ['store', 'update', 'destroy']),
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 파일 보기

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

+ 86
- 30
app/Http/Controllers/EndpointController.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
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
 use Illuminate\Http\Request;
10
 use Illuminate\Http\Request;
6
 use Illuminate\Support\Facades\Log;
11
 use Illuminate\Support\Facades\Log;
7
 use Illuminate\Support\Facades\Http;
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
 use App\DataTables\EndpointDataTableEditor;
14
 use App\DataTables\EndpointDataTableEditor;
15
+use App\DataTables\EndpointDataTable;
13
 use Illuminate\Support\Facades\Validator;
16
 use Illuminate\Support\Facades\Validator;
14
-use App\Models\Attivita;
15
-use Illuminate\Support\Str;
16
 use Illuminate\Support\Facades\Session;
17
 use Illuminate\Support\Facades\Session;
17
-use Illuminate\Support\Facades\Auth;
18
 use Illuminate\Support\Facades\Storage;
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
 class EndpointController extends Controller
23
 class EndpointController extends Controller
21
 {
24
 {
31
     public static function middleware(): array
34
     public static function middleware(): array
32
     {
35
     {
33
         return [
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
             new Middleware('permission:create-endpoint|edit-endpoint|delete-endpoint', only: ['store', 'update', 'destroy']),
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
             abort(404);
55
             abort(404);
53
         }
56
         }
54
 
57
 
58
+        AttivitaService::garantisciAttivita($endpoint->attivita_id);
59
+        
55
         return view('endpoint.show', compact('endpoint'));
60
         return view('endpoint.show', compact('endpoint'));
56
     }
61
     }
57
 
62
 
67
     //deeplink
72
     //deeplink
68
     public function collega_questo_pc(Request $request)
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
         ->where('user_id', $request->user()->id)
79
         ->where('user_id', $request->user()->id)
72
         ->where('status', Endpoint::NON_REGISTRATO)
80
         ->where('status', Endpoint::NON_REGISTRATO)
73
         ->first();
81
         ->first();
78
         }else{
86
         }else{
79
 
87
 
80
         $endpoint = new Endpoint();
88
         $endpoint = new Endpoint();
81
-        $endpoint->attivita_id = $request->attivita_id;
89
+        $endpoint->attivita_id = $attivitaId;
82
         $endpoint->user_id = $request->user()->id;
90
         $endpoint->user_id = $request->user()->id;
83
         $endpoint->deeplink_token = ['token' => Str::random(32) , 'timestamp' => now()->timestamp , 'status' => 'pending'];
91
         $endpoint->deeplink_token = ['token' => Str::random(32) , 'timestamp' => now()->timestamp , 'status' => 'pending'];
84
         $endpoint->product_key = $this->creaProductKey();
92
         $endpoint->product_key = $this->creaProductKey();
95
             'message' => 'Endpoint collegato con successo',
103
             'message' => 'Endpoint collegato con successo',
96
             'status' => 'success',
104
             'status' => 'success',
97
             'success' => true,
105
             'success' => true,
98
-            'endpoint' => $endpoint,
106
+            'endpoint' => $endpoint->makeHidden(['product_key', 'secret', 'deeplink_token', 'token']),
99
             'url' => url('fest-agent://pair?token=' . $endpoint->deeplink_token['token'] . '&server=' . $server),
107
             'url' => url('fest-agent://pair?token=' . $endpoint->deeplink_token['token'] . '&server=' . $server),
100
         ]);
108
         ]);
101
     }
109
     }
132
         }
140
         }
133
         $endpoint->update([
141
         $endpoint->update([
134
             'status' => Endpoint::DISABILITATO,
142
             'status' => Endpoint::DISABILITATO,
143
+            'token' => null,
135
         ]);
144
         ]);
136
         return response()->json([
145
         return response()->json([
137
             'message' => 'Endpoint disattivato con successo',
146
             'message' => 'Endpoint disattivato con successo',
145
             'token' => 'required|string|max:255',
154
             'token' => 'required|string|max:255',
146
         ]);
155
         ]);
147
         $endpoint = Endpoint::where('deeplink_token->token', $request->token)->first();
156
         $endpoint = Endpoint::where('deeplink_token->token', $request->token)->first();
157
+
158
+        //Se non c'è return
148
         if(!$endpoint){
159
         if(!$endpoint){
149
             return response()->json(['message' => 'Endpoint non trovato', 'status' => 'error', 'success' => false], 404);
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
         $deeplink_token = $endpoint->deeplink_token;
176
         $deeplink_token = $endpoint->deeplink_token;
152
         $deeplink_token['status'] = 'paired';
177
         $deeplink_token['status'] = 'paired';
153
         $endpoint->update([
178
         $endpoint->update([
154
-            'deeplink_token' => $deeplink_token,
179
+            'deeplink_token' => '',//$deeplink_token,
155
             'status' => Endpoint::REGISTRATO,
180
             'status' => Endpoint::REGISTRATO,
156
             'token' => Str::random(32),
181
             'token' => Str::random(32),
157
         ]);
182
         ]);
159
             'message' => 'Endpoint registrato con successo',
184
             'message' => 'Endpoint registrato con successo',
160
             'status' => 'success',
185
             'status' => 'success',
161
             'success' => true,
186
             'success' => true,
162
-            'endpoint' => $endpoint,
187
+            'endpoint' => $endpoint->makeHidden(['product_key', 'secret', 'deeplink_token']),
163
             'token' => $endpoint->token,
188
             'token' => $endpoint->token,
164
         ]);
189
         ]);
165
     }
190
     }
192
 
217
 
193
     public function stampanti_register(Request $request)
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
         $stampanti_da_registrare = $request->input('stampanti', []);
223
         $stampanti_da_registrare = $request->input('stampanti', []);
199
         $endpoint = $request->endpoint;
224
         $endpoint = $request->endpoint;
287
     public function esito_stampa(Request $request)
312
     public function esito_stampa(Request $request)
288
 {
313
 {
289
     $request->validate([
314
     $request->validate([
290
-        'printJob_id' => 'required|integer|exists:print_job,id',
315
+        'printJob_id' => 'required|integer',
291
         'esito' => 'required|string|in:success,error',
316
         'esito' => 'required|string|in:success,error',
292
     ]);
317
     ]);
293
 
318
 
294
     $printJob = PrintJob::query()
319
     $printJob = PrintJob::query()
295
         ->whereKey($request->printJob_id)
320
         ->whereKey($request->printJob_id)
321
+        ->whereIn(
322
+            'stampante_id',
323
+            $request->endpoint->stampanti()->pluck('id')
324
+        )
296
         ->first();
325
         ->first();
297
 
326
 
298
     if (! $printJob) {
327
     if (! $printJob) {
365
                     break;
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
         return $editor->process($request);
403
         return $editor->process($request);
369
     }
404
     }
370
     public function index_api(Request $request)
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
         return response()->json([
419
         return response()->json([
374
          'message' => 'Endpoint trovati con successo',
420
          'message' => 'Endpoint trovati con successo',
375
          'count' => $endpoints->count(),
421
          'count' => $endpoints->count(),
384
 
430
 
385
         if($request->has('first_time') && $request->first_time == true){
431
         if($request->has('first_time') && $request->first_time == true){
386
             //la prima registrazione
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
         $validator = Validator::make($request->all(), [
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
             'product_key.required' => 'Il product key è richiesto',
439
             'product_key.required' => 'Il product key è richiesto',
394
             'product_key.string' => 'Il product key deve essere una stringa',
440
             'product_key.string' => 'Il product key deve essere una stringa',
398
 
444
 
399
         if($validator->fails()){
445
         if($validator->fails()){
400
             Log::error('api_register_product_key');
446
             Log::error('api_register_product_key');
401
-            Log::error('Request: ' . $request->all());
447
+            // Log::error('Request: ' . $request->all());
402
             Log::error('Validator fails: ' . $validator->messages());
448
             Log::error('Validator fails: ' . $validator->messages());
403
             return response()->json([
449
             return response()->json([
404
                 'message' => $validator->messages(),
450
                 'message' => $validator->messages(),
416
                 'status' => 'error',
462
                 'status' => 'error',
417
                 'success' => false,
463
                 'success' => false,
418
             ], 404);
464
             ], 404);
419
-        }elseif($endpoint->status == Endpoint::REGISTRATO){
420
-            Log::error('Endpoint già registrato');
465
+        }elseif($endpoint->status != Endpoint::NON_REGISTRATO){
421
             return response()->json([
466
             return response()->json([
422
-                'message' => 'Endpoint già registrato',
467
+                'message' => 'Endpoint non può essere registrato',
423
                 'status' => 'error',
468
                 'status' => 'error',
424
                 'success' => false,
469
                 'success' => false,
425
             ], 400);
470
             ], 400);
451
             'message' => 'Endpoint trovato con successo',
496
             'message' => 'Endpoint trovato con successo',
452
             'status' => 'success',
497
             'status' => 'success',
453
             'success' => true,
498
             'success' => true,
454
-            'endpoint' => $endpoint,
499
+            'endpoint' => $endpoint->makeHidden(['product_key', 'secret', 'deeplink_token','token']),
455
             'licenza' => $licenza??null,
500
             'licenza' => $licenza??null,
456
             'attivita' => $attivita??null,
501
             'attivita' => $attivita??null,
457
         ]);
502
         ]);
460
         //se non è la prima registrazione può modificare gli attributi dell'endpoint
505
         //se non è la prima registrazione può modificare gli attributi dell'endpoint
461
         Log::info('api_register_product_key');
506
         Log::info('api_register_product_key');
462
         Log::info('NOT ft');
507
         Log::info('NOT ft');
463
-        Log::info('Request: ' . json_encode($request->all()));
508
+        // Log::info('Request: ' . json_encode($request->all()));
464
         // dd($request->all() , 'NOT ft');
509
         // dd($request->all() , 'NOT ft');
465
 
510
 
466
         $validator = Validator::make($request->all(), [
511
         $validator = Validator::make($request->all(), [
467
             'label' => 'required|string|max:255',
512
             'label' => 'required|string|max:255',
468
             'descrizione' => 'nullable|string|max:255',
513
             'descrizione' => 'nullable|string|max:255',
469
             'ubicazione' => 'nullable|string|max:255',
514
             'ubicazione' => 'nullable|string|max:255',
515
+            'product_key' => 'nullable|string|max:25|exists:endpoint,product_key',
470
         ], [
516
         ], [
471
             'label.required' => 'Il label è richiesto',
517
             'label.required' => 'Il label è richiesto',
472
             'label.string' => 'Il label deve essere una stringa',
518
             'label.string' => 'Il label deve essere una stringa',
475
             'descrizione.max' => 'La descrizione deve essere lungo al massimo 255 caratteri',
521
             'descrizione.max' => 'La descrizione deve essere lungo al massimo 255 caratteri',
476
             'ubicazione.string' => 'L\'ubicazione deve essere una stringa',
522
             'ubicazione.string' => 'L\'ubicazione deve essere una stringa',
477
             'ubicazione.max' => 'L\'ubicazione deve essere lungo al massimo 255 caratteri',
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
         if($validator->fails()){
529
         if($validator->fails()){
490
         $endpoint = Endpoint::where('product_key', $request->product_key)->where('status', Endpoint::REGISTRATO)->first();
539
         $endpoint = Endpoint::where('product_key', $request->product_key)->where('status', Endpoint::REGISTRATO)->first();
491
         if(!$endpoint){
540
         if(!$endpoint){
492
             Log::error('Endpoint non trovato');
541
             Log::error('Endpoint non trovato');
493
-            Log::error('Request: ' . json_encode($request->all()));
542
+            // Log::error('Request: ' . json_encode($request->all()));
494
             return response()->json([
543
             return response()->json([
495
                 'message' => 'Endpoint non trovato',
544
                 'message' => 'Endpoint non trovato',
496
                 'status' => 'error',
545
                 'status' => 'error',
510
             'message' => 'Endpoint aggiornato con successo',
559
             'message' => 'Endpoint aggiornato con successo',
511
             'status' => 'success',
560
             'status' => 'success',
512
             'success' => true,
561
             'success' => true,
513
-            'endpoint' => $endpoint,
562
+            'endpoint' => $endpoint->makeHidden(['product_key', 'secret', 'deeplink_token','token']),
514
             'token' => $endpoint->token,
563
             'token' => $endpoint->token,
515
         ]);
564
         ]);
516
 
565
 
527
             'attivita_id.exists' => 'L\'attività non è valida',
576
             'attivita_id.exists' => 'L\'attività non è valida',
528
         ]);
577
         ]);
529
 
578
 
579
+        AttivitaService::garantisciAttivita($request->attivita_id);
530
 
580
 
531
         $attivita = Attivita::find($request->attivita_id);
581
         $attivita = Attivita::find($request->attivita_id);
532
         
582
         
551
 
601
 
552
     public function download_festagent(Request $request)
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
         return Storage::disk('festAgent')->download('001_fest.exe', '001_fest.exe');   
610
         return Storage::disk('festAgent')->download('001_fest.exe', '001_fest.exe');   
555
     }
611
     }
556
 }
612
 }

+ 696
- 13
app/Http/Controllers/EventoController.php 파일 보기

4
 
4
 
5
 use Illuminate\Http\Request;
5
 use Illuminate\Http\Request;
6
 use App\Models\Evento;
6
 use App\Models\Evento;
7
+use App\Models\EventoForm;
8
+use App\Models\OpzioneForm;
9
+use App\Models\Prenotazione;
7
 use App\DataTables\EventoDataTable;
10
 use App\DataTables\EventoDataTable;
8
 use App\DataTables\EventoDataTableEditor;
11
 use App\DataTables\EventoDataTableEditor;
9
 use Illuminate\Support\Facades\Auth;
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
 class EventoController extends Controller
22
 class EventoController extends Controller
20
         'delete-evento' => 'Elimina',
29
         'delete-evento' => 'Elimina',
21
     ];
30
     ];
22
 
31
 
32
+    // ADMIN
23
     public static function middleware(): array
33
     public static function middleware(): array
24
     {
34
     {
25
         return [
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
     public function index(EventoDatatable $dataTable)
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
     public function store(EventoDataTableEditor $editor)
57
     public function store(EventoDataTableEditor $editor)
36
     {
58
     {
37
         $request = request();
59
         $request = request();
52
         return $editor->process($request);
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
         return view('evento.show', [
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
     public function gallery_edit(Request $request)
172
     public function gallery_edit(Request $request)
65
     {
173
     {
66
       $evento = Evento::find($request->get('evento_id'));
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
       return view('evento.gallery.edit', [
178
       return view('evento.gallery.edit', [
69
           'evento' => $evento,
179
           'evento' => $evento,
71
       ]);
181
       ]);
72
     }
182
     }
73
 
183
 
184
+    // ADMIN
74
     public function gallery_upload(Request $request)
185
     public function gallery_upload(Request $request)
75
     {
186
     {
76
       $evento = Evento::find($request->get('evento_id'));
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
       $galleria = json_decode($evento->galleria);
191
       $galleria = json_decode($evento->galleria);
78
       if($galleria == null) $galleria = [];
192
       if($galleria == null) $galleria = [];
79
       $nome = $request->file('file')->getClientOriginalName();
193
       $nome = $request->file('file')->getClientOriginalName();
86
       return redirect()->route('evento.gallery.edit', ['evento_id' => $evento->id])->with('success', 'Foto aggiunta con successo');
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
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\EventoForm;
8
 use App\Models\EventoForm;
7
 use App\Models\Evento;
9
 use App\Models\Evento;

+ 834
- 0
app/Http/Controllers/EventoPiantinaController.php 파일 보기

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
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\Fattura;
8
 use App\Models\Fattura;
7
 use App\DataTables\FatturaDataTable;
9
 use App\DataTables\FatturaDataTable;
22
 public static function middleware(): array
24
 public static function middleware(): array
23
 {
25
 {
24
     return [
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
     if(!Auth::user()->hasAnyRole(['superadmin','amministratore'])) return response()->json(['error' => 'Non hai i permessi per vedere una fattura'],403);
64
     if(!Auth::user()->hasAnyRole(['superadmin','amministratore'])) return response()->json(['error' => 'Non hai i permessi per vedere una fattura'],403);
63
 
65
 
64
     $fattura = Fattura::findOrFail($request->fattura_id);
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
     return view('fattura.show', compact('fattura'));
70
     return view('fattura.show', compact('fattura'));
66
 }
71
 }
67
 
72
 
74
 public function registra_pagamento(Request $request)
79
 public function registra_pagamento(Request $request)
75
 {
80
 {
76
     $fattura = Fattura::findOrFail($request->fattura_id);
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
     $fattura->stato = Fattura::PAGATA;
85
     $fattura->stato = Fattura::PAGATA;
78
     $fattura->info= json_encode(['pagamento_registrato_il' => now()]);
86
     $fattura->info= json_encode(['pagamento_registrato_il' => now()]);
79
     $fattura->save();
87
     $fattura->save();

+ 6
- 1
app/Http/Controllers/FornitoreController.php 파일 보기

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

+ 5
- 1
app/Http/Controllers/ImpostazioniController.php 파일 보기

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

+ 5
- 4
app/Http/Controllers/ListinoPrezziController.php 파일 보기

3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
 use Illuminate\Http\Request;
5
 use Illuminate\Http\Request;
6
+use Illuminate\Routing\Controllers\Middleware;
6
 use App\Models\ListinoPrezzi;
7
 use App\Models\ListinoPrezzi;
7
 use Illuminate\Support\Facades\Auth;
8
 use Illuminate\Support\Facades\Auth;
8
 use Illuminate\Support\Facades\Validator;
9
 use Illuminate\Support\Facades\Validator;
22
     
23
     
23
     public static function middleware(): array
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
     public function index(ListinoPrezziDataTable $dataTable)
32
     public function index(ListinoPrezziDataTable $dataTable)

+ 13
- 4
app/Http/Controllers/MappaDispositiviController.php 파일 보기

14
 use Illuminate\Support\Facades\Auth;
14
 use Illuminate\Support\Facades\Auth;
15
 use Illuminate\Support\Facades\Session;
15
 use Illuminate\Support\Facades\Session;
16
 use Illuminate\Routing\Controllers\Middleware;
16
 use Illuminate\Routing\Controllers\Middleware;
17
+use App\Services\Attivita\AttivitaService;
17
 
18
 
18
 class MappaDispositiviController extends Controller
19
 class MappaDispositiviController extends Controller
19
 {
20
 {
28
     public static function middleware(): array
29
     public static function middleware(): array
29
     {
30
     {
30
         return [
31
         return [
31
-            new Middleware('permission:view-mappa_dispositivi', only: ['index']),
32
+            new Middleware('permission:view-mappa_dispositivi', only: ['index', 'show']),
32
             new Middleware('permission:create-mappa_dispositivi|edit-mappa_dispositivi|delete-mappa_dispositivi', only: ['store', 'update', 'destroy']),
33
             new Middleware('permission:create-mappa_dispositivi|edit-mappa_dispositivi|delete-mappa_dispositivi', only: ['store', 'update', 'destroy']),
33
         ];
34
         ];
34
     }
35
     }
35
     
36
     
36
     public function index(DispositivoDataTable $dataTable)
37
     public function index(DispositivoDataTable $dataTable)
37
     {
38
     {
39
+        $dataTable->attivita_id = Session::get('attivita_attuale');
38
         if (request()->ajax()) {
40
         if (request()->ajax()) {
39
             return $dataTable->ajax();
41
             return $dataTable->ajax();
40
         }
42
         }
93
     public function show($dispositivo_id)
95
     public function show($dispositivo_id)
94
     {
96
     {
95
         $dispositivo = Dispositivo::find($dispositivo_id);
97
         $dispositivo = Dispositivo::find($dispositivo_id);
98
+        if (! $dispositivo) {
99
+            abort(404);
100
+        }
101
+        AttivitaService::garantisciAttivita($dispositivo->attivita_id);
102
+
96
         return view('mappa_dispositivi.show', ['dispositivo' => $dispositivo]);
103
         return view('mappa_dispositivi.show', ['dispositivo' => $dispositivo]);
97
     }
104
     }
98
 
105
 
105
         $grouped = array_fill_keys($tipi, []);
112
         $grouped = array_fill_keys($tipi, []);
106
         $grouped['_altro'] = [];
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
         $devices = Dispositivo::query()
121
         $devices = Dispositivo::query()
113
             ->with('attivita:id,nome')
122
             ->with('attivita:id,nome')

+ 3
- 1
app/Http/Controllers/MetodoPagamentoController.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\MetodoPagamento;
8
 use App\Models\MetodoPagamento;
7
 use App\DataTables\MetodoPagamentoDataTable;
9
 use App\DataTables\MetodoPagamentoDataTable;
23
     {
25
     {
24
         return [
26
         return [
25
             new Middleware('permission:view-metodo_pagamento', only: ['index']),
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
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\Dispositivo;
8
 use App\Models\Dispositivo;
7
 use App\Models\MonitorHasContenuto;
9
 use App\Models\MonitorHasContenuto;
11
 use Illuminate\Support\Facades\Auth;
13
 use Illuminate\Support\Facades\Auth;
12
 use Carbon\Carbon;
14
 use Carbon\Carbon;
13
 use Illuminate\Support\Facades\Session;
15
 use Illuminate\Support\Facades\Session;
16
+use App\Services\Attivita\AttivitaService;
14
 
17
 
15
 
18
 
16
 class MonitorController extends Controller
19
 class MonitorController extends Controller
26
     public static function middleware(): array
29
     public static function middleware(): array
27
     {
30
     {
28
         return [
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
         if($monitor == null){
64
         if($monitor == null){
62
             return redirect()->route('monitor.index')->with('error', 'Dispositivo monitor non trovato');
65
             return redirect()->route('monitor.index')->with('error', 'Dispositivo monitor non trovato');
63
         }
66
         }
67
+        AttivitaService::garantisciAttivita($monitor->attivita_id);
64
 
68
 
65
         $monitor_has_contenuto = MonitorHasContenuto::with(['cucina', 'contenuto_bacheca', 'bacheca.contenuti'])
69
         $monitor_has_contenuto = MonitorHasContenuto::with(['cucina', 'contenuto_bacheca', 'bacheca.contenuti'])
66
             ->where('monitor_id', $monitor->id)
70
             ->where('monitor_id', $monitor->id)
102
         if($monitor == null){
106
         if($monitor == null){
103
             abort(404, 'Dispositivo monitor non trovato');
107
             abort(404, 'Dispositivo monitor non trovato');
104
         }
108
         }
109
+        AttivitaService::garantisciAttivita($monitor->attivita_id);
105
         $monitor_has_contenuto = MonitorHasContenuto::where('monitor_id', $monitor->id)->first();
110
         $monitor_has_contenuto = MonitorHasContenuto::where('monitor_id', $monitor->id)->first();
106
 
111
 
107
         $bacheche = Bacheca::query()
112
         $bacheche = Bacheca::query()
146
 
151
 
147
         $isBacheca = (bool) $request->boolean('is_bacheca');
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
         MonitorHasContenuto::updateOrCreate([
172
         MonitorHasContenuto::updateOrCreate([
150
             'monitor_id' => $request->get('monitor_id'),
173
             'monitor_id' => $request->get('monitor_id'),
151
         ], [
174
         ], [

+ 26
- 3
app/Http/Controllers/OperatoreController.php 파일 보기

8
 use App\DataTables\OperatoreDataTableEditor;
8
 use App\DataTables\OperatoreDataTableEditor;
9
 use Illuminate\Support\Facades\Auth;
9
 use Illuminate\Support\Facades\Auth;
10
 use Illuminate\Routing\Controllers\Middleware;
10
 use Illuminate\Routing\Controllers\Middleware;
11
-use Illuminate\Routing\Controllers\HasMiddleware;
12
 use Illuminate\Support\Facades\Hash;
11
 use Illuminate\Support\Facades\Hash;
13
 use Illuminate\Support\Facades\Validator;
12
 use Illuminate\Support\Facades\Validator;
14
 use Illuminate\Support\Str;
13
 use Illuminate\Support\Str;
17
 use App\Models\Ordine;
16
 use App\Models\Ordine;
18
 use Illuminate\Support\Facades\Session;
17
 use Illuminate\Support\Facades\Session;
19
 use App\DataTables\RigaOrdineDataTable;
18
 use App\DataTables\RigaOrdineDataTable;
19
+use App\Services\Attivita\AttivitaService;
20
 
20
 
21
 
21
 
22
 class OperatoreController extends Controller
22
 class OperatoreController extends Controller
32
     public static function middleware(): array
32
     public static function middleware(): array
33
     {
33
     {
34
         return [
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
         if (!$operatore) {
50
         if (!$operatore) {
51
             return redirect()->back()->with('error', 'Operatore non trovato');
51
             return redirect()->back()->with('error', 'Operatore non trovato');
52
         }
52
         }
53
+        AttivitaService::garantisciAttivita($operatore->attivita_id);
53
         return view('operatore.show', ['operatore' => $operatore , 'dispositivi' => $operatore->dispositivi]);
54
         return view('operatore.show', ['operatore' => $operatore , 'dispositivi' => $operatore->dispositivi]);
54
     }
55
     }
55
 
56
 
56
     public function update_password(Request $request)
57
     public function update_password(Request $request)
57
     {
58
     {
58
         $operatore = Operatore::find($request->get('operatore_id'));
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
         $operatore->password = Hash::make($request->get('password'));
64
         $operatore->password = Hash::make($request->get('password'));
60
         $operatore->save();
65
         $operatore->save();
61
         return redirect()->route('operatore.show', ['operatore_id' => $operatore->id])->with('success', 'Password aggiornata con successo');
66
         return redirect()->route('operatore.show', ['operatore_id' => $operatore->id])->with('success', 'Password aggiornata con successo');
78
         if (!$operatore) {
83
         if (!$operatore) {
79
             return redirect()->back()->with('error', 'Operatore non trovato');
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
         $operatore->dispositivi()->sync($ids);
98
         $operatore->dispositivi()->sync($ids);
83
 
99
 
174
             return redirect()->route('punto-vendita.index')
190
             return redirect()->route('punto-vendita.index')
175
             ->with('error', 'Punto di vendita non trovato');
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
 // dd('A',$puntoVendita);
200
 // dd('A',$puntoVendita);
178
         if($puntoVendita->binding_token == '' || $puntoVendita->binding_token == null ){
201
         if($puntoVendita->binding_token == '' || $puntoVendita->binding_token == null ){
179
             $puntoVendita->binding_token = Hash::make(Str::random(32));
202
             $puntoVendita->binding_token = Hash::make(Str::random(32));

+ 24
- 2
app/Http/Controllers/OrdineController.php 파일 보기

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

+ 107
- 14
app/Http/Controllers/PagamentoController.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\Pagamento;
8
 use App\Models\Pagamento;
7
-use App\Models\MetodoPagamento;
9
+use App\Models\PrimaNota;
8
 use App\DataTables\PagamentoDataTable;
10
 use App\DataTables\PagamentoDataTable;
9
 use App\DataTables\PagamentoDataTableEditor;
11
 use App\DataTables\PagamentoDataTableEditor;
10
 use Illuminate\Support\Facades\Auth;
12
 use Illuminate\Support\Facades\Auth;
13
+use App\Services\Attivita\AttivitaService;
11
 
14
 
12
 class PagamentoController extends Controller
15
 class PagamentoController extends Controller
13
 {
16
 {
17
         'create-pagamento' => 'Crea',
20
         'create-pagamento' => 'Crea',
18
         'edit-pagamento' => 'Modifica',
21
         'edit-pagamento' => 'Modifica',
19
         'delete-pagamento' => 'Elimina',
22
         'delete-pagamento' => 'Elimina',
23
+        'storna-pagamento' => 'Storna',
20
     ];
24
     ];
21
 
25
 
22
     public static function middleware(): array
26
     public static function middleware(): array
23
     {
27
     {
24
         return [
28
         return [
25
-            new Middleware('permission:view-pagamento', only: ['index', 'show']),
29
+            new Middleware('permission:view-pagamento', only: ['index', 'show', 'show_modal']),
26
             new Middleware('permission:create-pagamento|edit-pagamento|delete-pagamento', only: ['store', 'update', 'destroy']),
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
     {
42
     {
38
         $request = request();
43
         $request = request();
39
         $input = $request->all();
44
         $input = $request->all();
40
-        if($request->has('action')){
41
-            switch($input['action']){
45
+        if ($request->has('action')) {
46
+            switch ($input['action']) {
42
                 case 'create':
47
                 case 'create':
43
-                    if(!Auth::user()->can('create-pagamento')) return;
48
+                    if (! Auth::user()->can('create-pagamento')) {
49
+                        return;
50
+                    }
44
                     break;
51
                     break;
45
                 case 'edit':
52
                 case 'edit':
46
-                    if(!Auth::user()->can('edit-pagamento')) return;
53
+                    if (! Auth::user()->can('edit-pagamento')) {
54
+                        return;
55
+                    }
47
                     break;
56
                     break;
48
                 case 'remove':
57
                 case 'remove':
49
-                    if(!Auth::user()->can('delete-pagamento')) return;
58
+                    if (! Auth::user()->can('delete-pagamento')) {
59
+                        return;
60
+                    }
50
                     break;
61
                     break;
51
-                }
62
+            }
63
+        }
64
+
52
         return $editor->process($request);
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
     public function show(Request $request)
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
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\Piatto;
8
 use App\Models\Piatto;
7
 use App\Models\PiattoHasAllergene;
9
 use App\Models\PiattoHasAllergene;
9
 use App\DataTables\PiattoDataTableEditor;
11
 use App\DataTables\PiattoDataTableEditor;
10
 use Illuminate\Support\Facades\Auth;
12
 use Illuminate\Support\Facades\Auth;
11
 use Illuminate\Support\Facades\Session;
13
 use Illuminate\Support\Facades\Session;
14
+use App\Services\Attivita\AttivitaService;
12
 
15
 
13
 class PiattoController extends Controller
16
 class PiattoController extends Controller
14
 {
17
 {
23
     public static function middleware(): array
26
     public static function middleware(): array
24
     {
27
     {
25
         return [
28
         return [
26
-            new Middleware('permission:view-piatto', only: ['index']),
29
+            new Middleware('permission:view-piatto', only: ['index', 'datatable']),
27
             new Middleware('permission:create-piatto|edit-piatto|delete-piatto', only: ['store', 'update', 'destroy']),
30
             new Middleware('permission:create-piatto|edit-piatto|delete-piatto', only: ['store', 'update', 'destroy']),
28
         ];
31
         ];
29
     }
32
     }
100
 
103
 
101
       foreach ($payload as $piattoId => $data) {
104
       foreach ($payload as $piattoId => $data) {
102
         $piattoId = (int) $piattoId;
105
         $piattoId = (int) $piattoId;
106
+        $piatto = Piatto::find($piattoId);
107
+        if (! $piatto) {
108
+          abort(404);
109
+        }
110
+        AttivitaService::garantisciAttivita($piatto->attivita_id);
111
+
103
         $allergenIds = $data['allergeni'] ?? [];
112
         $allergenIds = $data['allergeni'] ?? [];
104
 
113
 
105
         if (is_string($allergenIds)) {
114
         if (is_string($allergenIds)) {

+ 1326
- 49
app/Http/Controllers/PrenotazioneController.php
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 15
- 3
app/Http/Controllers/PrenotazioneTavoloController.php 파일 보기

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

+ 22
- 3
app/Http/Controllers/PrimaNotaController.php 파일 보기

9
 use App\DataTables\PrimaNotaDataTableEditor;
9
 use App\DataTables\PrimaNotaDataTableEditor;
10
 use Illuminate\Support\Facades\Auth;
10
 use Illuminate\Support\Facades\Auth;
11
 use Illuminate\Routing\Controllers\Middleware;
11
 use Illuminate\Routing\Controllers\Middleware;
12
+use App\Services\Attivita\AttivitaService;
12
 
13
 
13
 class PrimaNotaController extends Controller
14
 class PrimaNotaController extends Controller
14
 { 
15
 { 
23
     public static function middleware(): array
24
     public static function middleware(): array
24
     {
25
     {
25
         return [
26
         return [
26
-            new Middleware('permission:view-primanota', only: ['index', 'statistiche']),
27
+            new Middleware('permission:view-primanota', only: ['index', 'statistiche', 'show']),
27
             new Middleware('permission:create-primanota|edit-primanota|delete-primanota', only: ['store', 'update', 'destroy']),
28
             new Middleware('permission:create-primanota|edit-primanota|delete-primanota', only: ['store', 'update', 'destroy']),
28
         ];
29
         ];
29
     }
30
     }
88
                     break;
89
                     break;
89
                 }
90
                 }
90
         return $editor->process($request);
91
         return $editor->process($request);
92
+        }
91
     }
93
     }
92
-}
94
+
93
 
95
 
94
     public function show(Request $request)
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
         return view('prima_nota.show', compact('primanota'));
114
         return view('prima_nota.show', compact('primanota'));
98
     }
115
     }
116
+
117
+
99
 }
118
 }

+ 12
- 2
app/Http/Controllers/PrintJobController.php 파일 보기

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

+ 6
- 1
app/Http/Controllers/PuntoOperatoreController.php 파일 보기

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

+ 85
- 38
app/Http/Controllers/PuntoVenditaController.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use App\DataTables\PuntoVenditaDataTable;
7
 use App\DataTables\PuntoVenditaDataTable;
6
 use App\DataTables\PuntoVenditaDataTableEditor;
8
 use App\DataTables\PuntoVenditaDataTableEditor;
7
 use App\DataTables\RigaOrdineDataTable;
9
 use App\DataTables\RigaOrdineDataTable;
8
 
10
 
9
 use App\Models\Dispositivo;
11
 use App\Models\Dispositivo;
12
+use App\Models\Cucina;
10
 use App\Models\Ordine;
13
 use App\Models\Ordine;
11
 use App\Models\Pagamento;
14
 use App\Models\Pagamento;
12
 use App\Models\RigaOrdine;
15
 use App\Models\RigaOrdine;
14
 use App\Models\SaltacodaOrdine;
17
 use App\Models\SaltacodaOrdine;
15
 use App\Models\SaltacodaRigaOrdine;
18
 use App\Models\SaltacodaRigaOrdine;
16
 use App\Models\SaltacodaRigaOrdineHasVariante;
19
 use App\Models\SaltacodaRigaOrdineHasVariante;
20
+use App\Services\Attivita\AttivitaService;
17
 
21
 
18
 use Illuminate\Support\Str;
22
 use Illuminate\Support\Str;
19
 use Illuminate\Http\Request;
23
 use Illuminate\Http\Request;
37
     public static function middleware(): array
41
     public static function middleware(): array
38
     {
42
     {
39
         return [
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
             return redirect()->route('punto-vendita.index')
68
             return redirect()->route('punto-vendita.index')
59
                 ->with('error', 'Punto di vendita non trovato');
69
                 ->with('error', 'Punto di vendita non trovato');
60
         }
70
         }
71
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
61
 
72
 
62
         return view('punto_vendita.dettaglio_punto_vendita', compact('puntoVendita'));
73
         return view('punto_vendita.dettaglio_punto_vendita', compact('puntoVendita'));
63
     }
74
     }
70
             return redirect()->route('punto-vendita.index')
81
             return redirect()->route('punto-vendita.index')
71
                 ->with('error', 'Punto di vendita non trovato');
82
                 ->with('error', 'Punto di vendita non trovato');
72
         }
83
         }
84
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
73
 
85
 
74
         return view('punto_vendita.edit', ['puntoVendita' => $puntoVendita]);
86
         return view('punto_vendita.edit', ['puntoVendita' => $puntoVendita]);
75
     }
87
     }
82
             return redirect()->route('punto-vendita.index')
94
             return redirect()->route('punto-vendita.index')
83
                 ->with('error', 'Punto di vendita non trovato');
95
                 ->with('error', 'Punto di vendita non trovato');
84
         }
96
         }
97
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
85
 
98
 
86
         if (Auth::user()->can('edit-punto_vendita')) {
99
         if (Auth::user()->can('edit-punto_vendita')) {
87
 
100
 
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
             if ($request->has('info')) {
160
             if ($request->has('info')) {
139
                 $validated['info'] = json_decode($request->info, true);
161
                 $validated['info'] = json_decode($request->info, true);
140
             }
162
             }
141
             if ($request->has('url_stampante')) {
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
             $puntoVendita->update($validated);
171
             $puntoVendita->update($validated);
158
         if (! $puntoVendita) {
182
         if (! $puntoVendita) {
159
             return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
183
             return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
160
         }
184
         }
185
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
161
 
186
 
162
         if (Auth::user()->can('edit-punto_vendita')) {
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
             $puntoVendita->hasCucine()->sync($cucine_ids);
199
             $puntoVendita->hasCucine()->sync($cucine_ids);
165
 
200
 
166
             return response()->json(['success' => true, 'message' => 'Cucine associate con successo']);
201
             return response()->json(['success' => true, 'message' => 'Cucine associate con successo']);
210
             return redirect()->route('punto-vendita.index')
245
             return redirect()->route('punto-vendita.index')
211
                 ->with('error', 'Punto di vendita non trovato');
246
                 ->with('error', 'Punto di vendita non trovato');
212
         }
247
         }
213
-
248
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
249
+        
214
         if($puntoVendita->attivita->user_id != Auth::user()->id){
250
         if($puntoVendita->attivita->user_id != Auth::user()->id){
215
             session(['attivita_attuale' => null]);
251
             session(['attivita_attuale' => null]);
216
             Cookie::queue(Cookie::forget('binding_token'));
252
             Cookie::queue(Cookie::forget('binding_token'));
285
                     if ($isDataTableDrawRequest) {
321
                     if ($isDataTableDrawRequest) {
286
                         // Prosegue senza interrompere la risposta DataTable.
322
                         // Prosegue senza interrompere la risposta DataTable.
287
                     } else {
323
                     } else {
288
-                        dd('11, altro dispositivo', json_encode(request()->cookie()));
289
-
290
                         return redirect()->route('punto-vendita.index')->with('error', 'Dispositivo già occupato. Dissociare per potervi accedere.');
324
                         return redirect()->route('punto-vendita.index')->with('error', 'Dispositivo già occupato. Dissociare per potervi accedere.');
291
                     }
325
                     }
292
                 }
326
                 }
346
         if (! $puntoVendita) {
380
         if (! $puntoVendita) {
347
             return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
381
             return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
348
         }
382
         }
349
-
383
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
384
+        
350
         Cookie::queue(Cookie::forget('binding_token'));
385
         Cookie::queue(Cookie::forget('binding_token'));
351
 
386
 
352
         $puntoVendita->binding_token = null;
387
         $puntoVendita->binding_token = null;
363
             return redirect()->route('punto-vendita.kiosk.index')
398
             return redirect()->route('punto-vendita.kiosk.index')
364
                 ->with('error', 'Ordine non trovato');
399
                 ->with('error', 'Ordine non trovato');
365
         }
400
         }
401
+        AttivitaService::garantisciAttivita($ordine->attivita_id);
366
 
402
 
367
         return view('punto_vendita.kiosk.riepilogo', ['ordine' => $ordine]);
403
         return view('punto_vendita.kiosk.riepilogo', ['ordine' => $ordine]);
368
     }
404
     }
374
             return redirect()->route('punto-vendita.index')
410
             return redirect()->route('punto-vendita.index')
375
                 ->with('error', 'Punto di vendita non trovato');
411
                 ->with('error', 'Punto di vendita non trovato');
376
         }
412
         }
377
-
413
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
414
+        
378
         return view('punto_vendita.dettagli', ['puntoVendita' => $puntoVendita]);
415
         return view('punto_vendita.dettagli', ['puntoVendita' => $puntoVendita]);
379
     }
416
     }
380
 
417
 
385
             return redirect()->route('punto-vendita.index')
422
             return redirect()->route('punto-vendita.index')
386
                 ->with('error', 'Punto di vendita non trovato');
423
                 ->with('error', 'Punto di vendita non trovato');
387
         }
424
         }
388
-        // Calcola la data di oggi
425
+        AttivitaService::garantisciAttivita($puntoVendita->attivita_id);
426
+        
389
         $oggi = now()->startOfDay();
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
             ->whereDate('created_at', $oggi)
433
             ->whereDate('created_at', $oggi)
394
             ->get();
434
             ->get();
395
 
435
 
396
-        // Conta il totale ordini di oggi
397
         $totaleOrdiniOggi = $ordiniOggi->count();
436
         $totaleOrdiniOggi = $ordiniOggi->count();
398
-
399
         $ordineIds = $ordiniOggi->pluck('id')->all();
437
         $ordineIds = $ordiniOggi->pluck('id')->all();
400
 
438
 
401
         if ($ordineIds === []) {
439
         if ($ordineIds === []) {
403
             $pagamentiPerMetodo = [];
441
             $pagamentiPerMetodo = [];
404
             $pagamentiConteggioPerMetodo = [];
442
             $pagamentiConteggioPerMetodo = [];
405
         } else {
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
                 ->whereIn('ordine_id', $ordineIds)
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
                 ->selectRaw('metodo_pagamento_id, SUM(importo) as totale_importo')
452
                 ->selectRaw('metodo_pagamento_id, SUM(importo) as totale_importo')
415
                 ->groupBy('metodo_pagamento_id')
453
                 ->groupBy('metodo_pagamento_id')
416
                 ->pluck('totale_importo', 'metodo_pagamento_id')
454
                 ->pluck('totale_importo', 'metodo_pagamento_id')
417
                 ->map(fn ($v) => (float) $v)
455
                 ->map(fn ($v) => (float) $v)
418
                 ->all();
456
                 ->all();
419
 
457
 
420
-            $pagamentiConteggioPerMetodo = Pagamento::query()
421
-                ->whereIn('ordine_id', $ordineIds)
458
+            $pagamentiConteggioPerMetodo = (clone $pagamentiBase)
422
                 ->selectRaw('metodo_pagamento_id, COUNT(*) as conteggio')
459
                 ->selectRaw('metodo_pagamento_id, COUNT(*) as conteggio')
423
                 ->groupBy('metodo_pagamento_id')
460
                 ->groupBy('metodo_pagamento_id')
424
                 ->pluck('conteggio', 'metodo_pagamento_id')
461
                 ->pluck('conteggio', 'metodo_pagamento_id')
438
     public function cerca_pre_ordine(Request $request)
475
     public function cerca_pre_ordine(Request $request)
439
     {
476
     {
440
         $codice = $request->get('codice');
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
         return view('punto_vendita.cassa._partials.pre_ordine', ['pre_ordine' => $pre_ordine]);
504
         return view('punto_vendita.cassa._partials.pre_ordine', ['pre_ordine' => $pre_ordine]);
467
     public function importa_pre_ordine(Request $request)
509
     public function importa_pre_ordine(Request $request)
468
 {
510
 {
469
     $codice = (string) $request->get('codice');
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
     if (! Session::has('attivita_attuale') || Session::get('attivita_attuale') === null) {
517
     if (! Session::has('attivita_attuale') || Session::get('attivita_attuale') === null) {
472
         return response()->json(['success' => false, 'message' => 'Attività non trovata']);
518
         return response()->json(['success' => false, 'message' => 'Attività non trovata']);
492
             if (! $ordine || $ordine->stato !== Ordine::CARRELLO) {
538
             if (! $ordine || $ordine->stato !== Ordine::CARRELLO) {
493
                 return response()->json(['success' => false, 'message' => 'Ordine non valido']);
539
                 return response()->json(['success' => false, 'message' => 'Ordine non valido']);
494
             }
540
             }
541
+            AttivitaService::garantisciAttivita($ordine->attivita_id);
495
 
542
 
496
             $isPrimoImport = $pre_ordine->stato === SaltacodaOrdine::PRE_ORDINE;
543
             $isPrimoImport = $pre_ordine->stato === SaltacodaOrdine::PRE_ORDINE;
497
             $isRipristino = $pre_ordine->stato === SaltacodaOrdine::PRE_CARRELLO
544
             $isRipristino = $pre_ordine->stato === SaltacodaOrdine::PRE_CARRELLO

+ 916
- 166
app/Http/Controllers/ReportController.php
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 2
- 0
app/Http/Controllers/RigaFatturazioneController.php 파일 보기

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

+ 13
- 9
app/Http/Controllers/RigaOrdineController.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use Illuminate\Database\Eloquent\Builder;
8
 use Illuminate\Database\Eloquent\Builder;
7
 use App\Models\Dispositivo;
9
 use App\Models\Dispositivo;
23
     public static function middleware(): array
25
     public static function middleware(): array
24
     {
26
     {
25
         return [
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
     public function lista_da_chiamare(Request $request){
45
     public function lista_da_chiamare(Request $request){

+ 2
- 2
app/Http/Controllers/RigaOrdineNotificaController.php 파일 보기

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

+ 3
- 1
app/Http/Controllers/RoleController.php 파일 보기

33
   public static function middleware(): array
33
   public static function middleware(): array
34
   {
34
   {
35
     return [
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
       new Middleware('permission:create-role|edit-role|remove-role', only: ['store']),
39
       new Middleware('permission:create-role|edit-role|remove-role', only: ['store']),
38
     ];
40
     ];
39
   }
41
   }

+ 334
- 60
app/Http/Controllers/SaltacodaController.php 파일 보기

2
 
2
 
3
 namespace App\Http\Controllers;
3
 namespace App\Http\Controllers;
4
 
4
 
5
+
6
+use Illuminate\Routing\Controllers\Middleware;
5
 use Illuminate\Http\Request;
7
 use Illuminate\Http\Request;
6
 use App\Models\Attivita;
8
 use App\Models\Attivita;
7
 use App\Models\Cucina;
9
 use App\Models\Cucina;
8
 use App\Models\Piatto;
10
 use App\Models\Piatto;
9
 use App\Models\Saltacoda;
11
 use App\Models\Saltacoda;
10
 use App\Models\SaltacodaOrdine;
12
 use App\Models\SaltacodaOrdine;
11
-use App\Models\SaltacodaRigaordine;
13
+use App\Models\SaltacodaRigaOrdine;
12
 use App\Models\VariantePiatto;
14
 use App\Models\VariantePiatto;
13
 use App\Models\SaltacodaRigaOrdineHasVariante;
15
 use App\Models\SaltacodaRigaOrdineHasVariante;
14
 use Illuminate\Support\Facades\DB;
16
 use Illuminate\Support\Facades\DB;
17
+use Illuminate\Support\Str;
18
+use App\Services\Attivita\AttivitaService;
15
 
19
 
16
 
20
 
17
 class SaltacodaController extends Controller
21
 class SaltacodaController extends Controller
28
     {
32
     {
29
         return [
33
         return [
30
             new Middleware('permission:view-saltacoda', only: ['index']),
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
             'istruzioni' => 'nullable|json',
80
             'istruzioni' => 'nullable|json',
77
         ]);
81
         ]);
78
 
82
 
83
+        AttivitaService::garantisciAttivita($request->attivita_id);
84
+
79
         $saltacoda = Saltacoda::updateOrCreate(
85
         $saltacoda = Saltacoda::updateOrCreate(
80
             ['attivita_id' => $request->attivita_id],
86
             ['attivita_id' => $request->attivita_id],
81
             [
87
             [
90
         return redirect()->route('saltacoda.index')->with('success', 'Saltacoda salvato');
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
         if(!$attivita) {
104
         if(!$attivita) {
97
             return response()->json([
105
             return response()->json([
98
                 'success' => false,
106
                 'success' => false,
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
         return view('saltacoda.show', [
202
         return view('saltacoda.show', [
180
             'attivita' => $attivita,
203
             'attivita' => $attivita,
181
             'cucine' => $cucine,
204
             'cucine' => $cucine,
183
             'saltacoda_id' => $saltacoda->id,
206
             'saltacoda_id' => $saltacoda->id,
184
             'varianti_per_piatto' => $variantiPerPiatto,
207
             'varianti_per_piatto' => $variantiPerPiatto,
185
             'varianti_per_cucina' => $variantiPerCucina,
208
             'varianti_per_cucina' => $variantiPerCucina,
209
+            'ordine_in_modifica' => $ordineInModifica,
210
+            'avvisi_modifica' => $avvisiModifica,
186
         ]);
211
         ]);
187
     }
212
     }
188
 
213
 
189
     public function pre_ordine_salva(Request $request)
214
     public function pre_ordine_salva(Request $request)
190
-    {
215
+    {       
191
         $request->validate([
216
         $request->validate([
192
             'saltacoda_id' => 'required|exists:saltacoda,id',
217
             'saltacoda_id' => 'required|exists:saltacoda,id',
193
             'attivita_id' => 'required|exists:attivita,id',
218
             'attivita_id' => 'required|exists:attivita,id',
199
             'riga_ordine.*.varianti.*' => 'integer|exists:variante_piatto,id',
224
             'riga_ordine.*.varianti.*' => 'integer|exists:variante_piatto,id',
200
             'info_cliente' => 'nullable|array',
225
             'info_cliente' => 'nullable|array',
201
             'idempotency_key' => 'nullable|string|max:120',
226
             'idempotency_key' => 'nullable|string|max:120',
227
+            'codice' => 'nullable|string|max:9',
228
+            't' => 'nullable|string|max:64',
202
         ]);
229
         ]);
203
 
230
 
204
         $saltacoda = Saltacoda::where('id', $request->saltacoda_id)
231
         $saltacoda = Saltacoda::where('id', $request->saltacoda_id)
211
             ], 422);
238
             ], 422);
212
         }
239
         }
213
 
240
 
241
+        $isModifica = $request->filled('codice');
242
+
214
         try {
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
                 $saltacoda_ordine->fill([
271
                 $saltacoda_ordine->fill([
225
-                    'riferimento' => $request->idempotency_key,
226
                     'attivita_id' => $request->attivita_id,
272
                     'attivita_id' => $request->attivita_id,
227
                     'info' => $request->info_cliente,
273
                     'info' => $request->info_cliente,
228
                     'prenotazione_id' => null,
274
                     'prenotazione_id' => null,
236
                 $saltacoda_ordine->save();
282
                 $saltacoda_ordine->save();
237
 
283
 
238
                 $saltacoda_ordine->saltacoda_riga_ordine()->delete();
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
                 $saltacoda_ordine->prezzo = $saltacoda_ordine->saltacoda_riga_ordine()->sum('prezzo');
287
                 $saltacoda_ordine->prezzo = $saltacoda_ordine->saltacoda_riga_ordine()->sum('prezzo');
284
                 $saltacoda_ordine->save();
288
                 $saltacoda_ordine->save();
289
                 ]);
293
                 ]);
290
             });
294
             });
291
 
295
 
292
-            return response()->json([
296
+            $json = response()->json([
293
                 'success' => true,
297
                 'success' => true,
294
-                'message' => 'Pre-ordine salvato',
298
+                'message' => $isModifica ? 'Pre-ordine aggiornato' : 'Pre-ordine salvato',
295
                 'data' => $saltacoda_ordine,
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
         } catch (\InvalidArgumentException $exception) {
319
         } catch (\InvalidArgumentException $exception) {
298
             return response()->json([
320
             return response()->json([
299
                 'success' => false,
321
                 'success' => false,
304
 
326
 
305
     public function pre_ordine_show(Request $request)
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
         $saltacoda_ordine = SaltacodaOrdine::query()
338
         $saltacoda_ordine = SaltacodaOrdine::query()
308
             ->with([
339
             ->with([
309
                 'saltacoda_riga_ordine.piatto',
340
                 'saltacoda_riga_ordine.piatto',
310
                 'saltacoda_riga_ordine.saltacoda_has_variante.variante_piatto',
341
                 'saltacoda_riga_ordine.saltacoda_has_variante.variante_piatto',
311
                 'attivita',
342
                 'attivita',
312
             ])
343
             ])
313
-            ->where('codice', $request->get('codice'))
344
+            ->where('codice', $codice)
345
+            ->where('token', $token)
314
             ->first();
346
             ->first();
315
         if(!$saltacoda_ordine) {
347
         if(!$saltacoda_ordine) {
316
             return abort(404);
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
     private function calcolaPrezzoRigaSaltacoda(Piatto $piatto, int $qta, $varianti): float
595
     private function calcolaPrezzoRigaSaltacoda(Piatto $piatto, int $qta, $varianti): float
338
         $parteLettera = $lettereSicure[rand(0, count($lettereSicure) - 1)];
612
         $parteLettera = $lettereSicure[rand(0, count($lettereSicure) - 1)];
339
         $parteCifre2 = str_pad(strval(rand(0, 99)), 2, '0', STR_PAD_LEFT);
613
         $parteCifre2 = str_pad(strval(rand(0, 99)), 2, '0', STR_PAD_LEFT);
340
         $parteCifre3 = str_pad(strval(rand(0, 999)), 3, '0', STR_PAD_LEFT);
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
         if (SaltacodaOrdine::where('codice', $codice)->exists()) {
617
         if (SaltacodaOrdine::where('codice', $codice)->exists()) {
344
             return $this->genera_codice_saltacoda();
618
             return $this->genera_codice_saltacoda();

+ 2
- 0
app/Http/Controllers/StampanteController.php 파일 보기

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

+ 2
- 0
app/Http/Controllers/TavoloController.php 파일 보기

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

+ 9
- 2
app/Http/Controllers/TestiController.php 파일 보기

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

+ 8
- 8
app/Http/Controllers/TombolaController.php 파일 보기

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

+ 3
- 1
app/Http/Controllers/UserController.php 파일 보기

50
   public static function middleware(): array
50
   public static function middleware(): array
51
   {
51
   {
52
     return [
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
       new Middleware('permission:create-user|edit-user|remove-user', only: ['store', 'admin_aggiorna']),
56
       new Middleware('permission:create-user|edit-user|remove-user', only: ['store', 'admin_aggiorna']),
55
       new Middleware('role:superadmin', only: ['superadmin_impersonate']),
57
       new Middleware('role:superadmin', only: ['superadmin_impersonate']),
56
     ];
58
     ];

+ 0
- 0
app/Http/Controllers/VariantePiattoController.php 파일 보기


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.

Loading…
취소
저장