Explorar el Código

Cassa e carrello: checkout, binding dispositivo e import saltacoda.

Rimosso il dump sulla cassa occupata; il carrello resta l'ordine in sessione.

Co-authored-by: Cursor <cursoragent@cursor.com>
marcofalabretti hace 2 semanas
padre
commit
fdef65ba82

+ 30
- 8
app/DataTables/OrdineDataTableEditor.php Ver fichero

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

+ 12
- 12
app/DataTables/PiattoDataTable.php Ver fichero

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

+ 28
- 7
app/DataTables/PiattoDataTableEditor.php Ver fichero

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

+ 8
- 1
app/DataTables/PuntoVenditaDataTable.php Ver fichero

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

+ 17
- 14
app/DataTables/PuntoVenditaDataTableEditor.php Ver fichero

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

+ 13
- 0
app/Http/Controllers/AsportoController.php Ver fichero

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

+ 114
- 72
app/Http/Controllers/CarrelloController.php Ver fichero

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

+ 26
- 3
app/Http/Controllers/OperatoreController.php Ver fichero

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

+ 24
- 2
app/Http/Controllers/OrdineController.php Ver fichero

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

+ 10
- 1
app/Http/Controllers/PiattoController.php Ver fichero

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

+ 6
- 1
app/Http/Controllers/PuntoOperatoreController.php Ver fichero

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

+ 85
- 38
app/Http/Controllers/PuntoVenditaController.php Ver fichero

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

+ 13
- 9
app/Http/Controllers/RigaOrdineController.php Ver fichero

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

+ 2
- 2
app/Http/Controllers/RigaOrdineNotificaController.php Ver fichero

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

+ 1
- 1
app/Models/AbstractModels/AbstractOrdine.php Ver fichero

@@ -82,7 +82,7 @@ abstract class AbstractOrdine extends \Illuminate\Foundation\Auth\User
82 82
 
83 83
     public function punto_vendita()
84 84
     {
85
-        return $this->belongsTo('\App\Models\PuntoVendita', 'punto_vendita_id', 'id');
85
+        return $this->belongsTo('\App\Models\Dispositivo', 'punto_vendita_id', 'id');
86 86
     }
87 87
 
88 88
     public function prenotazione()

+ 112
- 73
app/Services/Carrello/CarrelloService.php Ver fichero

@@ -5,34 +5,81 @@ namespace App\Services\Carrello;
5 5
 use App\Models\Ordine;
6 6
 use App\Models\RigaOrdine;
7 7
 use App\Models\Piatto;
8
+use App\Models\Dispositivo;
8 9
 use App\Models\SaltacodaOrdine;
9 10
 use App\Models\VariantePiatto;
10 11
 use App\Models\RigaOrdineHasVariante;
11
-use Illuminate\Database\Eloquent\ModelNotFoundException;
12
+use App\Services\Attivita\AttivitaService;
12 13
 
13 14
 class CarrelloService
14 15
 {
15
-    public function findCartOrFail(int $ordineId): Ordine
16
+    /**
17
+     * @return array{0: int, 1: int} [attivitaId, dispositivoId]
18
+     */
19
+    public function contestoCassa(): array
16 20
     {
17
-        $ordine = Ordine::find($ordineId);
21
+        $attivitaId = (int) (session('attivita_attuale') ?: session('attivita_id'));
22
+        $dispositivoId = (int) session('dispositivo_id');
23
+        if ($attivitaId <= 0 || $dispositivoId <= 0) {
24
+            abort(404);
25
+        }
26
+
27
+        AttivitaService::garantisciAttivita($attivitaId);
28
+
29
+        $dispositivo = Dispositivo::find($dispositivoId);
30
+        if (! $dispositivo || (int) $dispositivo->attivita_id !== $attivitaId) {
31
+            abort(404);
32
+        }
33
+
34
+        return [$attivitaId, $dispositivoId];
35
+    }
18 36
 
19
-        if (! $ordine) {
20
-            throw new ModelNotFoundException('Ordine non trovato.');
37
+    public function carrelloDiQuestaCassa(int $ordineId): Ordine
38
+    {
39
+        [$attivitaId, $dispositivoId] = $this->contestoCassa();
40
+        $ordine = Ordine::find($ordineId);
41
+        if (
42
+            ! $ordine
43
+            || (int) $ordine->attivita_id !== $attivitaId
44
+            || (int) $ordine->dispositivo_id !== $dispositivoId
45
+            || $ordine->stato !== Ordine::CARRELLO
46
+        ) {
47
+            abort(404);
21 48
         }
22 49
 
23 50
         return $ordine;
24 51
     }
25 52
 
26
-    public function aumentaQuantita(int $dispositivo_id ,?int $attivita_id, ?int $ordine_id, int $piatto_id, ?int $riga_ordine_id = null): array
53
+    public function rigaDiQuestaCassa(int $rigaId): RigaOrdine
54
+    {
55
+        $riga = RigaOrdine::find($rigaId);
56
+        if (! $riga) {
57
+            abort(404);
58
+        }
59
+
60
+        $this->carrelloDiQuestaCassa((int) $riga->ordine_id);
61
+
62
+        return $riga;
63
+    }
64
+
65
+    public function findCartOrFail(int $ordineId): Ordine
66
+    {
67
+        return $this->carrelloDiQuestaCassa($ordineId);
68
+    }
69
+
70
+    public function aumentaQuantita(?int $ordine_id, int $piatto_id, ?int $riga_ordine_id = null): array
27 71
     {
28
-    // Tolleranza su ordine_id stale: se non e` valido, usa/crea il carrello corrente per dispositivo+attivita.
72
+        [$attivitaId, $dispositivoId] = $this->contestoCassa();
73
+
74
+        $piatto = Piatto::where('id', $piatto_id)->where('attivita_id', $attivitaId)->first();
75
+        if (! $piatto) {
76
+            abort(404);
77
+        }
78
+
29 79
         $carrelloBaseQuery = Ordine::query()
30 80
             ->where('stato', Ordine::CARRELLO)
31
-            ->where('dispositivo_id', $dispositivo_id)
32
-            ->when(
33
-                $attivita_id,
34
-                fn ($q) => $q->where('attivita_id', $attivita_id)
35
-            );
81
+            ->where('dispositivo_id', $dispositivoId)
82
+            ->where('attivita_id', $attivitaId);
36 83
 
37 84
         $carrello = null;
38 85
         if ($ordine_id) {
@@ -41,21 +88,26 @@ class CarrelloService
41 88
                 ->first();
42 89
         }
43 90
 
44
-        if (!$carrello) {
91
+        if (! $carrello) {
45 92
             $carrello = (clone $carrelloBaseQuery)->latest('id')->first();
46 93
         }
47 94
 
48
-        if (!$carrello) {
95
+        if (! $carrello) {
49 96
             $carrello = Ordine::create([
50 97
                 'stato' => Ordine::CARRELLO,
51
-                'dispositivo_id' => $dispositivo_id,
52
-                'attivita_id' => $attivita_id,
98
+                'dispositivo_id' => $dispositivoId,
99
+                'attivita_id' => $attivitaId,
53 100
             ]);
54 101
         }
55 102
 
56
-        if($riga_ordine_id){
57
-            $riga = RigaOrdine::findOrFail($riga_ordine_id);
58
-        }else{
103
+        if ($riga_ordine_id) {
104
+            $riga = RigaOrdine::where('id', $riga_ordine_id)
105
+                ->where('ordine_id', $carrello->id)
106
+                ->first();
107
+            if (! $riga) {
108
+                abort(404);
109
+            }
110
+        } else {
59 111
             $riga = RigaOrdine::where('ordine_id', $carrello->id)->where('piatto_id', $piatto_id)->whereDoesntHave('has_variante')->oldest('id')->first();
60 112
         }
61 113
         // else{
@@ -97,25 +149,26 @@ class CarrelloService
97 149
 
98 150
     public function diminuisciQuantita(int $ordine_id, int $piatto_id, int $riga_ordine_id): array
99 151
     {
100
-        $carrello = Ordine::findOrFail($ordine_id);
101
-        // $riga = RigaOrdine::where('ordine_id', $carrello->id)->where('piatto_id', $piatto_id)->first();
102
-        $riga = RigaOrdine::findOrFail($riga_ordine_id);
103
-        if($riga && $riga->id == $riga_ordine_id){
104
-            // $piatto = Piatto::findOrFail($piatto_id);
105
-            $piatto = $riga->piatto;
106
-            $riga->quantita -= 1;
152
+        $carrello = $this->carrelloDiQuestaCassa($ordine_id);
153
+        $riga = RigaOrdine::where('id', $riga_ordine_id)->where('ordine_id', $carrello->id)->first();
154
+        if (! $riga) {
155
+            abort(404);
156
+        }
107 157
 
108
-            if($riga->quantita == 0){
109
-                $riga->delete();
110
-                return [
111
-                    'ordine' => $carrello,
112
-                    'riga' => null,
113
-                ];
114
-            };
158
+        $riga->quantita -= 1;
115 159
 
116
-            $riga->prezzo = $this->calcolaPrezzoRiga($riga);
117
-            $riga->save();   
160
+        if ($riga->quantita == 0) {
161
+            $riga->delete();
162
+
163
+            return [
164
+                'ordine' => $carrello,
165
+                'riga' => null,
166
+            ];
118 167
         }
168
+
169
+        $riga->prezzo = $this->calcolaPrezzoRiga($riga);
170
+        $riga->save();
171
+
119 172
         return [
120 173
             'ordine' => $carrello,
121 174
             'riga' => $riga,
@@ -124,23 +177,15 @@ class CarrelloService
124 177
 
125 178
     public function eliminaRiga(int $rigaOrdineId, bool $elimina = false): void
126 179
     {
127
-        $riga = RigaOrdine::find($rigaOrdineId);
128
-        if($riga !== null && $elimina){
129
-        $riga->delete();
130
-        };
180
+        $riga = $this->rigaDiQuestaCassa($rigaOrdineId);
181
+        if ($elimina) {
182
+            $riga->delete();
183
+        }
131 184
     }
132 185
 
133 186
     public function azzeraCarrello(int $ordine_id): array
134 187
     {
135
-        $ordine = Ordine::find($ordine_id);
136
-
137
-        if($ordine == null){
138
-            return [
139
-                'success' => false,
140
-                'message' => 'Ordine non trovato',
141
-                'data' => null,  
142
-            ];
143
-        }
188
+        $ordine = $this->carrelloDiQuestaCassa($ordine_id);
144 189
 
145 190
         $preOrdineId = data_get($ordine->info, 'pre_ordine_id');
146 191
         $preOrdineCodice = data_get($ordine->info, 'pre_ordine_codice');
@@ -187,20 +232,17 @@ class CarrelloService
187 232
 
188 233
     public function aggiornaNota(int $rigaOrdineId, string $note = null): RigaOrdine
189 234
     {
190
-        $riga = RigaOrdine::findOrFail($rigaOrdineId);
191
-        if($riga == null){
192
-            throw new ModelNotFoundException('Riga ordine non trovata.');
193
-        };
194
-
235
+        $riga = $this->rigaDiQuestaCassa($rigaOrdineId);
195 236
         $riga->note = $note;
196 237
         $riga->save();
238
+
197 239
         return $riga;
198 240
     }
199 241
 
200 242
     public function aggiungiVarianteSingoloPiatto(int $piattoId, int $rigaOrdineId, array $varianteIds, string $nota = null): array
201 243
     {
202 244
         $varianteIds = array_values(array_unique(array_map('intval', array_filter($varianteIds))));
203
-    
245
+
204 246
         if (empty($varianteIds)) {
205 247
             return [
206 248
                 'success' => false,
@@ -208,9 +250,13 @@ class CarrelloService
208 250
                 'data' => null,
209 251
             ];
210 252
         }
211
-    
212
-        $riga = RigaOrdine::findOrFail($rigaOrdineId);
213
-        $piatto = Piatto::findOrFail($piattoId);
253
+
254
+        $riga = $this->rigaDiQuestaCassa($rigaOrdineId);
255
+        [$attivitaId] = $this->contestoCassa();
256
+        $piatto = Piatto::where('id', $piattoId)->where('attivita_id', $attivitaId)->first();
257
+        if (! $piatto) {
258
+            abort(404);
259
+        }
214 260
         $targetRiga = $riga;
215 261
     
216 262
         // qty > 1: splitta una volta, poi tutte le varianti vanno sulla nuova riga
@@ -233,7 +279,10 @@ class CarrelloService
233 279
         $aggiunte = 0;
234 280
     
235 281
         foreach ($varianteIds as $varianteId) {
236
-            VariantePiatto::findOrFail($varianteId);
282
+            $variante = VariantePiatto::where('id', $varianteId)->where('attivita_id', $attivitaId)->first();
283
+            if (! $variante) {
284
+                abort(404);
285
+            }
237 286
     
238 287
             $giaPresente = RigaOrdineHasVariante::where('riga_ordine_id', $targetRiga->id)
239 288
                 ->where('variante_id', $varianteId)
@@ -273,21 +322,11 @@ class CarrelloService
273 322
 
274 323
     public function eliminaVariante(int $rigaOrdineId, int $varianteId): array
275 324
     {
276
-        $riga = RigaOrdine::findOrFail($rigaOrdineId);
277
-        if($riga == null){
278
-            return [
279
-                'success' => false,
280
-                'message' => 'Riga ordine non trovata.',
281
-                'data' => null,
282
-            ];
283
-        }
284
-        $variante = VariantePiatto::findOrFail($varianteId);
285
-        if($variante == null){
286
-            return [
287
-                'success' => false,
288
-                'message' => 'Variante non trovata.',
289
-                'data' => null,
290
-            ];
325
+        $riga = $this->rigaDiQuestaCassa($rigaOrdineId);
326
+        [$attivitaId] = $this->contestoCassa();
327
+        $variante = VariantePiatto::where('id', $varianteId)->where('attivita_id', $attivitaId)->first();
328
+        if (! $variante) {
329
+            abort(404);
291 330
         }
292 331
         $pivotVariante = RigaOrdineHasVariante::where('riga_ordine_id', $riga->id)->where('variante_id', $varianteId)->first();
293 332
         if($pivotVariante == null){

+ 4
- 4
resources/js/ordine-notifica.js Ver fichero

@@ -82,14 +82,14 @@ btn?.addEventListener('click', async () => {
82 82
 
83 83
     const fcmToken = await chiediTokenFcm();
84 84
 
85
-    const ordineId = btn.dataset.ordineId;
86
-    if (!ordineId) {
87
-      throw new Error('ID ordine non trovato nella pagina');
85
+    const ordineCodice = btn.dataset.ordineCodice;
86
+    if (!ordineCodice) {
87
+      throw new Error('Codice ordine non trovato nella pagina');
88 88
     }
89 89
 
90 90
     const body = new FormData();
91 91
     body.append('fcm_token', fcmToken);
92
-    body.append('ordine_id', ordineId);
92
+    body.append('ordine_codice', ordineCodice);
93 93
 
94 94
     const res = await fetch(window.subscribeUrl, {
95 95
       method: 'POST',

+ 1
- 0
resources/views/operatore/show.blade.php Ver fichero

@@ -103,6 +103,7 @@ div.dt-action-buttons .dt-buttons .btn:last-child {
103 103
         <form action="{{ route('operatore.update.password', $operatore->id) }}" method="post">
104 104
           @csrf
105 105
           @method('POST')
106
+          <input type="hidden" name="operatore_id" value="{{ $operatore->id }}">
106 107
           <div class="mb-3">
107 108
             <label for="password" class="form-label">Password</label>
108 109
             <input type="password" class="form-control" id="password" name="password">

+ 373
- 309
resources/views/ordine/show.blade.php Ver fichero

@@ -1,356 +1,420 @@
1
-<?php
2
-use App\Models\Role;
3
-use Illuminate\Support\Facades\Auth;
4
-?>
5 1
 @php
6
-$configData = Helper::appClasses();
7
-@endphp
2
+use App\Models\Ordine;
3
+use App\Models\RigaOrdine;
4
+use Illuminate\Support\Str;
8 5
 
9
-@extends('layouts/layoutMaster')
6
+$tipoMeta = $ordine->tipo ? (Ordine::getTipi()->get($ordine->tipo) ?? []) : [];
7
+$totale = $ordine->prezzo !== null
8
+    ? (float) $ordine->prezzo
9
+    : (float) $ordine->righe_ordine->sum('prezzo');
10
+$nRighe = $ordine->righe_ordine->count();
11
+$nPezzi = (int) $ordine->righe_ordine->sum('quantita');
12
+$datiCassa = is_array($ordine->info) ? $ordine->info : [];
13
+$infoLabels = [
14
+    'cliente' => 'Cliente',
15
+    'tavolo' => 'Tavolo',
16
+    'coperti' => 'Coperti',
17
+];
18
+$infoVisibili = collect($datiCassa)
19
+    ->reject(fn ($valore) => $valore === null || $valore === '' || $valore === [])
20
+    ->all();
21
+$cliente = $datiCassa['cliente'] ?? null;
22
+$tavolo = $datiCassa['tavolo'] ?? null;
23
+$coperti = $datiCassa['coperti'] ?? null;
24
+$isCarrello = $ordine->stato === Ordine::CARRELLO;
10 25
 
11
-@section('title', 'Ordini')
26
+$iconePagamento = [
27
+    'carta_di_credito' => 'bx-credit-card',
28
+    'carta_di_debito' => 'bx-credit-card',
29
+    'bonifico' => 'bx-transfer',
30
+    'paypal' => 'bx-paypal',
31
+    'stripe' => 'bx-credit-card',
32
+    'contanti' => 'bx-money',
33
+    'credito' => 'bx-wallet',
34
+    'apple_pay' => 'bx-mobile',
35
+    'google_pay' => 'bx-mobile',
36
+    'cupon' => 'bx-purchase-tag',
37
+    'segresta_wallet' => 'bx-wallet',
38
+    'pos' => 'bx-credit-card',
39
+    'staff' => 'bx-id-card',
40
+];
41
+@endphp
12 42
 
13
-@section('vendor-style')
14
-@vite([
15
-'resources/assets/vendor/libs/datatables-bs5/datatables.bootstrap5.scss',
16
-'resources/assets/vendor/libs/datatables-responsive-bs5/responsive.bootstrap5.scss',
17
-'resources/assets/vendor/libs/datatables-buttons-bs5/buttons.bootstrap5.scss',
18
-'resources/assets/vendor/libs/flatpickr/flatpickr.scss',
19
-'resources/assets/vendor/libs/@form-validation/form-validation.scss'
20
-])
21
-@endsection
43
+@extends('layouts/layoutMaster')
22 44
 
23
-<!-- Vendor Scripts -->
24
-@section('vendor-script')
25
-@vite([
26
-'resources/assets/vendor/libs/moment/moment.js',
27
-'resources/assets/vendor/libs/flatpickr/flatpickr.js',
28
-'resources/assets/vendor/libs/@form-validation/popular.js',
29
-'resources/assets/vendor/libs/@form-validation/bootstrap5.js',
30
-'resources/assets/vendor/libs/@form-validation/auto-focus.js',
31
-'resources/assets/vendor/libs/@form-validation/popular.js',
32
-'resources/assets/vendor/libs/@form-validation/bootstrap5.js',
33
-'resources/assets/vendor/libs/@form-validation/auto-focus.js',
34
-'resources/assets/vendor/libs/datatables-bs5/datatables-bootstrap5.js'
35
-])
36
-@endsection
45
+@section('title', 'Ordine #'.$ordine->id)
37 46
 
38 47
 @section('pageTitle')
39 48
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-receipt"></i> Ordine #{{ $ordine->id }}
42
-    <small class="text-muted">{{ view('prenotazione._partials.stato-prenotazione', ['stato' => $ordine->stato]) }}</small>
43
-</h4>
49
+  <h4 class="mb-0 text-sm-small">
50
+    <i class="bx bx-receipt d-none d-md-inline-flex"></i>
51
+    Dettaglio ordine
52
+  </h4>
53
+  <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block">
54
+    <ol class="breadcrumb breadcrumb-custom-icon mb-0">
55
+      <li class="breadcrumb-item">
56
+        <a href="{{ route('ordine.index') }}">Ordini</a>
57
+        <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
58
+      </li>
59
+      <li class="breadcrumb-item active text-primary">#{{ $ordine->id }}</li>
60
+    </ol>
61
+  </nav>
44 62
 </div>
45 63
 @endsection
46 64
 
47 65
 @section('content')
66
+@include('_partials.status')
67
+
48 68
 <style>
49
-  div.upload button:first-child{
50
-    display: none !important;
69
+  .or-show-hero {
70
+    border: 1px solid rgba(67, 89, 113, .12);
71
+    border-radius: 1rem;
72
+    overflow: hidden;
73
+    background: var(--bs-paper-bg, #fff);
74
+  }
75
+  .or-show-hero__main {
76
+    display: flex;
77
+    flex-wrap: wrap;
78
+    align-items: center;
79
+    justify-content: space-between;
80
+    gap: 1.25rem;
81
+    padding: 1.35rem 1.5rem;
82
+  }
83
+  .or-show-hero__amount {
84
+    font-size: clamp(1.75rem, 4vw, 2.35rem);
85
+    font-weight: 700;
86
+    line-height: 1.1;
87
+    letter-spacing: -0.02em;
88
+    color: var(--bs-heading-color);
89
+  }
90
+  .or-show-hero__meta {
91
+    display: flex;
92
+    flex-wrap: wrap;
93
+    align-items: center;
94
+    gap: .5rem;
95
+  }
96
+  .or-show-hero__title {
97
+    font-size: 1.15rem;
98
+    font-weight: 600;
99
+    margin-bottom: .35rem;
100
+  }
101
+  .or-show-hero__sub {
102
+    color: var(--bs-secondary-color);
103
+    font-size: .875rem;
104
+  }
105
+  .or-show-section-title {
106
+    font-size: .8rem;
107
+    font-weight: 600;
108
+    text-transform: uppercase;
109
+    letter-spacing: .04em;
110
+    color: var(--bs-secondary-color);
111
+    margin-bottom: .75rem;
112
+  }
113
+  .or-show-dl dt {
114
+    color: var(--bs-secondary-color);
115
+    font-weight: 500;
116
+    font-size: .8125rem;
117
+  }
118
+  .or-show-dl dd {
119
+    font-size: .9375rem;
120
+    margin-bottom: .65rem;
121
+  }
122
+  .or-show-link-card {
123
+    display: flex;
124
+    align-items: center;
125
+    gap: .85rem;
126
+    padding: .85rem 1rem;
127
+    border: 1px solid rgba(67, 89, 113, .12);
128
+    border-radius: .75rem;
129
+    background: var(--bs-paper-bg, #fff);
130
+    transition: border-color .15s ease, box-shadow .15s ease;
131
+  }
132
+  .or-show-link-card:hover {
133
+    border-color: rgba(var(--bs-primary-rgb), .35);
134
+    box-shadow: 0 .125rem .5rem rgba(67, 89, 113, .08);
135
+  }
136
+  .or-show-link-card--empty {
137
+    opacity: .72;
138
+    background: rgba(67, 89, 113, .03);
139
+  }
140
+  .or-show-link-card__icon {
141
+    width: 2.5rem;
142
+    height: 2.5rem;
143
+    border-radius: .65rem;
144
+    display: flex;
145
+    align-items: center;
146
+    justify-content: center;
147
+    flex-shrink: 0;
148
+    background: rgba(var(--bs-primary-rgb), .1);
149
+    color: var(--bs-primary);
150
+    font-size: 1.25rem;
151
+  }
152
+  .or-show-link-card--empty .or-show-link-card__icon {
153
+    background: rgba(67, 89, 113, .08);
154
+    color: var(--bs-secondary-color);
155
+  }
156
+  .or-show-link-card__body { flex: 1; min-width: 0; }
157
+  .or-show-link-card__label {
158
+    font-size: .75rem;
159
+    color: var(--bs-secondary-color);
160
+    margin-bottom: .1rem;
161
+  }
162
+  .or-show-link-card__title {
163
+    font-weight: 600;
164
+    font-size: .9375rem;
165
+    line-height: 1.3;
166
+  }
167
+  .or-show-link-card__subtitle {
168
+    font-size: .8125rem;
169
+    color: var(--bs-secondary-color);
170
+    margin-top: .15rem;
171
+  }
172
+  .or-show-qty {
173
+    min-width: 2.25rem;
174
+    height: 2.25rem;
175
+    border-radius: .65rem;
176
+    display: inline-flex;
177
+    align-items: center;
178
+    justify-content: center;
179
+    font-weight: 700;
180
+    background: rgba(var(--bs-primary-rgb), .1);
181
+    color: var(--bs-primary);
182
+  }
183
+  .or-show-line + .or-show-line {
184
+    border-top: 1px solid rgba(67, 89, 113, .1);
51 185
   }
52
-
53
-.bx-chef-hat{
54
-  --svg: url("data:image/svg+xml,%3csvg width='24' height='24' fill='currentColor' viewBox='0 0 24 24' transform='' xmlns='http://www.w3.org/2000/svg'%3e%3c!--Boxicons v3.0.8 https://boxicons.com %7c License https://docs.boxicons.com/free--%3e%3cpath d='M17.13 5.54C16.33 3.42 14.32 2 12 2S7.67 3.42 6.87 5.54A5.506 5.506 0 0 0 2 11c0 2.07 1.18 3.95 3 4.88V18c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-2.12c1.82-.93 3-2.81 3-4.88 0-2.82-2.13-5.15-4.87-5.46m.53 8.75c-.4.14-.67.52-.67.94v1.78H7v-1.78c0-.42-.27-.8-.67-.94-1.4-.5-2.33-1.82-2.33-3.28 0-1.93 1.57-3.5 3.42-3.5.04 0 .14.01.18.02.49 0 .9-.31 1-.78.36-1.61 1.76-2.73 3.41-2.73s3.05 1.12 3.41 2.73c.1.47.51.81 1 .78.06 0 .12 0 .09-.01 1.93 0 3.5 1.57 3.5 3.5 0 1.47-.94 2.79-2.33 3.28ZM5 20h14v2H5z'%3e%3c/path%3e%3c/svg%3e");
55
-}
56
-
57
-.report-list-item-li:hover{
58
-    transition: box-shadow 0.3s;
59
-    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
60
-    cursor: pointer;
61
-}
62
-
63
-
64 186
 </style>
65 187
 
66
-@include('_partials.status')
188
+<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
189
+  <a href="{{ route('ordine.index') }}" class="btn btn-label-secondary btn-sm">
190
+    <i class="bx bx-arrow-back me-1"></i> Torna agli ordini
191
+  </a>
192
+  <span class="text-muted small">ID ordine <strong>#{{ $ordine->id }}</strong></span>
193
+</div>
67 194
 
68
-@include('ordine._partials.card_statistiche')
195
+<div class="or-show-hero mb-4">
196
+  <div class="or-show-hero__main">
197
+    <div class="flex-grow-1 min-w-0">
198
+      <div class="or-show-hero__meta mb-2">
199
+        @include('prenotazione._partials.stato-prenotazione', ['stato' => $ordine->stato])
200
+        @if(!empty($tipoMeta['label']))
201
+          <span class="badge bg-label-info">{{ $tipoMeta['label'] }}</span>
202
+        @endif
203
+        @if($ordine->dispositivo)
204
+          <span class="badge bg-label-secondary">{{ $ordine->dispositivo->nome }}</span>
205
+        @endif
206
+        @if($ordine->codice && strlen((string) $ordine->codice) <= 12)
207
+          <span class="badge bg-label-primary">Codice {{ $ordine->codice }}</span>
208
+        @endif
209
+      </div>
69 210
 
70
-<div class="row justify-content-center">
211
+      <div class="or-show-hero__title">
212
+        Ordine #{{ $ordine->id }}
213
+        @if(filled($cliente))
214
+          · {{ $cliente }}
215
+        @endif
216
+      </div>
71 217
 
72
-  <!-- Card 1: Informazioni Ordine -->
73
-  <div class="col-12 col-md-4 col-xl-3 mb-4 mt-2">
74
-    <div class="card h-100">
75
-      <div class="card-header d-flex align-items-center justify-content-between">
76
-        <h5 class="card-title m-0 me-2">Informazioni ordine</h5>
218
+      <div class="or-show-hero__sub">
219
+        <i class="bx bx-time-five me-1"></i>
220
+        {{ $ordine->created_at?->format('d/m/Y') }} alle {{ $ordine->created_at?->format('H:i') }}
221
+        @if(filled($tavolo))
222
+          · Tavolo {{ $tavolo }}
223
+        @endif
224
+        @if(filled($coperti) && (int) $coperti > 0)
225
+          · {{ $coperti }} coperti
226
+        @endif
227
+        · {{ $nPezzi }} {{ $nPezzi === 1 ? 'articolo' : 'articoli' }}
77 228
       </div>
78
-      <div class="card-body">
79
-      <div class="mb-3">
80
-          <p><strong>Dispositivo:</strong> {{ $ordine->dispositivo->nome ?? '-' }}</p>
81
-        </div>
82
-      <div class="mb-3">
83
-          <p><strong>Data creazione:</strong> {{ $ordine->created_at->format('d/m/Y H:i') }}</p>
84
-        </div>
85
-        <div class="mb-3">
86
-          <p><strong>Stato:</strong> 
87
-            {!! view('prenotazione._partials.stato-prenotazione', ['stato' => $ordine->stato]) !!}
88
-          </p>
89
-        </div>
90
-        <div class="mb-3">
91
-          <p><strong>Tipo:</strong> {{ $ordine->tipo ?? '-' }}</p>
92
-        </div>
93
-        <div class="mb-3">
94
-          <p><strong>Riferimento:</strong> {{ $ordine->riferimento ?? '-' }}</p>
95
-        </div>
96
-        <div class="mb-3">
97
-          <p><strong>Note:</strong> {{ $ordine->note ?? '-' }}</p>
98
-        </div>
99
-        @if($ordine->info)
100
-        <div class="mb-3">
101
-          <p><strong>Info extra:</strong>
102
-            @php
103
-              $infoArr = is_array($ordine->info) ? $ordine->info : (json_decode($ordine->info, true) ?? []);
104
-            @endphp
105
-            @if(!empty($infoArr))
106
-                @foreach($infoArr as $key => $value)
107
-                  <span class="d-block"><strong>{{ ucfirst($key) }}:</strong> {{ $value }}</span>
108
-                @endforeach
109
-            @endif
110
-          </p>
111
-        </div>
229
+    </div>
230
+
231
+    <div class="text-end">
232
+      <div class="or-show-hero__amount">€ {{ number_format($totale, 2, ',', '.') }}</div>
233
+      <div class="text-muted small mt-1">
234
+        @if($isCarrello)
235
+          Totale carrello
236
+        @else
237
+          Totale ordine
112 238
         @endif
113 239
       </div>
114 240
     </div>
115 241
   </div>
242
+</div>
116 243
 
117
-  <!-- Card 2: Piatti -->
118
-  <div class="col-12 col-md-6 col-xl-5 mb-4 mt-2">
244
+<div class="row g-4">
245
+  <div class="col-12 col-lg-8">
119 246
     <div class="card h-100">
120
-      <div class="card-header d-flex align-items-center justify-content-between">
121
-        <h5 class="card-title m-0 me-2">Piatti</h5>
122
-        <div class="dropdown">
123
-          <button class="btn text-muted p-0" type="button" id="transactionID" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
124
-            <i class="bx bx-dots-vertical-rounded bx-lg"></i>
125
-          </button>
126
-          <div class="dropdown-menu dropdown-menu-end" aria-labelledby="transactionID">
127
-            <a class="dropdown-item" href="javascript:void(0);">Last 28 Days</a>
128
-            <a class="dropdown-item" href="javascript:void(0);">Last Month</a>
129
-            <a class="dropdown-item" href="javascript:void(0);">Last Year</a>
130
-          </div>
247
+      <div class="card-body">
248
+        <div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
249
+          <div class="or-show-section-title mb-0">Articoli</div>
250
+          <span class="badge bg-label-secondary">{{ $nRighe }} {{ $nRighe === 1 ? 'riga' : 'righe' }}</span>
131 251
         </div>
132
-      </div>
133
-      <div class="card-body pt-4">
134
-        <ul class="p-0 m-0">
135
-        @foreach($ordine->righe_ordine as $riga)  
136
-        <li class="d-flex align-items-center mb-6">
137
-            <div class="d-flex align-items-center gap-2 justify-content-center w-px-50 fs-4">
138
-                <span class="fw-normal mb-0">{{ $riga->quantita }} x</span>
139
-            </div>
140 252
 
141
-            <div class="avatar flex-shrink-0 me-3">
142
-                @if($riga->piatto->immagine)
143
-                  <img src="{{asset('assets/img/piatti/'.$riga->piatto->immagine)}}" alt="User" class="rounded">
144
-                @else
145
-                  <span class="avatar-icon bx bx-dish rounded" style="font-size:2rem; color: #ccc; display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; background: #f0f0f0;"></span>
146
-                @endif
147
-            </div>
148
-            <div class="d-flex w-100 flex-wrap align-items-center justify-content-between gap-2">
149
-              <div class="me-2">
150
-                <h6 class="mb-0">{{ $riga->piatto->nome }}</h6>
151
-                <small class="d-block mb-2">{{ \Illuminate\Support\Str::limit($riga->piatto->descrizione, 50) }}</small>
152
-                @if($riga->note)
153
-                  <small class="d-block text-muted"><i class="bx bx-chat me-2 text-warning"></i> {{ $riga->note }}</small>
154
-                @endif
155
-                @if($riga->piatto->elencoAllergeni->isNotEmpty())
156
-                  <small class="d-block text-muted"><i class="bx bx-info-circle me-2 text-warning"></i> Allergeni: {{ $riga->piatto->elencoAllergeni->implode(', ') }}</small>
157
-                @endif
158
-              </div>
159
-              <div class="user-progress d-flex align-items-center gap-2">
160
-                 <span class="text-muted"> € {{ number_format($riga->piatto->prezzo, 2, ',', '.') }}</span>
253
+        @forelse($ordine->righe_ordine as $riga)
254
+          @php
255
+            $piatto = $riga->piatto;
256
+            $varianti = ($riga->has_variante ?? collect())->filter(fn ($v) => $v->variante_id !== null);
257
+            $allergeni = $piatto?->elencoAllergeni?->pluck('nome')->filter()->implode(', ');
258
+            $statoRiga = RigaOrdine::getStati()->get($riga->stato);
259
+          @endphp
260
+          <div class="or-show-line py-3 d-flex align-items-start gap-3">
261
+            <div class="or-show-qty">{{ (int) $riga->quantita }}</div>
262
+            <div class="flex-grow-1 min-w-0">
263
+              <div class="d-flex flex-wrap justify-content-between gap-2">
264
+                <div class="fw-semibold">{{ $piatto->nome ?? ('Piatto #'.$riga->piatto_id) }}</div>
265
+                <div class="fw-semibold text-nowrap">€ {{ number_format((float) $riga->prezzo, 2, ',', '.') }}</div>
161 266
               </div>
267
+
268
+              @if($piatto?->cucina?->nome)
269
+                <div class="small text-muted">{{ $piatto->cucina->nome }}</div>
270
+              @endif
271
+
272
+              @foreach($varianti as $variante)
273
+                <div class="small text-muted">
274
+                  <i class="bx bx-plus-circle me-1"></i>
275
+                  {{ $variante->variante_piatto->label ?? 'Variante' }}
276
+                  @if(filled($variante->nota))
277
+                    <em>({{ $variante->nota }})</em>
278
+                  @endif
279
+                </div>
280
+              @endforeach
281
+
282
+              @if(filled($riga->note))
283
+                <div class="small text-warning">
284
+                  <i class="bx bx-chat me-1"></i>{{ $riga->note }}
285
+                </div>
286
+              @endif
287
+
288
+              @if(filled($allergeni))
289
+                <div class="small text-muted">
290
+                  <i class="bx bx-info-circle me-1"></i>Allergeni: {{ $allergeni }}
291
+                </div>
292
+              @endif
293
+
294
+              @if(!empty($statoRiga['label']) && $riga->stato && $riga->stato !== RigaOrdine::ORDINATO)
295
+                <span class="badge bg-label-secondary mt-1">{{ $statoRiga['label'] }}</span>
296
+              @endif
162 297
             </div>
163
-          </li>
164
-        @endforeach
165
-        </ul>
298
+          </div>
299
+        @empty
300
+          <p class="text-muted mb-0">Nessun articolo in questo ordine.</p>
301
+        @endforelse
166 302
       </div>
167 303
     </div>
168 304
   </div>
169 305
 
170
-  <!-- Card 3: Riepilogo Prezzo ed Entità Collegate -->
171
-  <div class="col-12 col-md-6 col-xl-4 mb-4 mt-2">
172
-    <div class="card h-100">
173
-      <div class="card-header d-flex align-items-center justify-content-between">
174
-        <h5 class="card-title m-0 me-2">Riepilogo Ordine</h5>
306
+  <div class="col-12 col-lg-4">
307
+    <div class="card mb-4">
308
+      <div class="card-body">
309
+        <div class="or-show-section-title">Informazioni</div>
310
+        <dl class="row or-show-dl mb-0">
311
+          <dt class="col-5">Cassa</dt>
312
+          <dd class="col-7 fw-medium">{{ $ordine->dispositivo?->nome ?? '—' }}</dd>
313
+
314
+          <dt class="col-5">Creato</dt>
315
+          <dd class="col-7">{{ $ordine->created_at?->format('d/m/Y H:i') ?? '—' }}</dd>
316
+
317
+          @if($ordine->updated_at && $ordine->updated_at->ne($ordine->created_at))
318
+            <dt class="col-5">Aggiornato</dt>
319
+            <dd class="col-7">{{ $ordine->updated_at->format('d/m/Y H:i') }}</dd>
320
+          @endif
321
+
322
+          @if(!empty($tipoMeta['label']))
323
+            <dt class="col-5">Tipo</dt>
324
+            <dd class="col-7">{{ $tipoMeta['label'] }}</dd>
325
+          @endif
326
+
327
+          @if(filled($ordine->riferimento))
328
+            <dt class="col-5">Riferimento</dt>
329
+            <dd class="col-7">{{ $ordine->riferimento }}</dd>
330
+          @endif
331
+
332
+          @if(filled($ordine->codice))
333
+            <dt class="col-5">Codice</dt>
334
+            <dd class="col-7 text-break">{{ $ordine->codice }}</dd>
335
+          @endif
336
+        </dl>
337
+
338
+        @if(filled($ordine->note))
339
+          <div class="or-show-section-title mt-3">Note</div>
340
+          <p class="mb-0">{{ $ordine->note }}</p>
341
+        @endif
342
+
343
+        @if($infoVisibili !== [])
344
+          <div class="or-show-section-title mt-3">Dati raccolti in cassa</div>
345
+          <dl class="row or-show-dl mb-0">
346
+            @foreach($infoVisibili as $chiave => $valore)
347
+              <dt class="col-5">{{ $infoLabels[$chiave] ?? Str::headline((string) $chiave) }}</dt>
348
+              <dd class="col-7">
349
+                @if(is_array($valore) || is_object($valore))
350
+                  <code>{{ json_encode($valore, JSON_UNESCAPED_UNICODE) }}</code>
351
+                @elseif(in_array($chiave, ['asporto'], true) || is_bool($valore))
352
+                  {{ filter_var($valore, FILTER_VALIDATE_BOOLEAN) ? 'Sì' : 'No' }}
353
+                @else
354
+                  {{ $valore }}
355
+                @endif
356
+              </dd>
357
+            @endforeach
358
+          </dl>
359
+        @endif
175 360
       </div>
361
+    </div>
362
+
363
+    <div class="card">
176 364
       <div class="card-body">
177
-        <div class="mb-4">
178
-          <h6 class="fw-bold mb-2">Totale Ordine</h6>
179
-          <div class="fs-3 fw-bold text-success">
180
-            @if($ordine->prezzo != null)
181
-            € {{ number_format($ordine->prezzo, 2, ',', '.') }} 
182
-            @else
183
-            € {{ number_format($ordine->righe_ordine->sum('prezzo'), 2, ',', '.') }} <small class="text-muted text-grey">(carrello aperto)</small>
184
-            @endif
185
-          </div>
186
-        </div>
187
-        <div class="mb-3">
188
-          <h6 class="fw-bold mb-2">Prenotazione</h6>
365
+        <div class="or-show-section-title">Collegamenti</div>
366
+        <div class="d-flex flex-column gap-3">
189 367
           @if($ordine->prenotazione)
190
-            {!! view('prenotazione._partials.btn-link', ['prenotazione' => $ordine->prenotazione]) !!}
368
+            <a href="{{ route('prenotazione.show', ['prenotazione_id' => $ordine->prenotazione_id]) }}" class="or-show-link-card text-body text-decoration-none">
369
+              <div class="or-show-link-card__icon"><i class="bx bx-calendar-check"></i></div>
370
+              <div class="or-show-link-card__body">
371
+                <div class="or-show-link-card__label">Prenotazione</div>
372
+                <div class="or-show-link-card__title">{{ $ordine->prenotazione->label() }}</div>
373
+                @if(filled($ordine->prenotazione->email))
374
+                  <div class="or-show-link-card__subtitle">{{ $ordine->prenotazione->email }}</div>
375
+                @endif
376
+              </div>
377
+              <i class="bx bx-chevron-right text-muted"></i>
378
+            </a>
191 379
           @else
192
-            <span class="badge bg-label-secondary">Nessuna prenotazione associata</span>
380
+            <div class="or-show-link-card or-show-link-card--empty">
381
+              <div class="or-show-link-card__icon"><i class="bx bx-calendar-check"></i></div>
382
+              <div class="or-show-link-card__body">
383
+                <div class="or-show-link-card__label">Prenotazione</div>
384
+                <div class="or-show-link-card__title text-muted">Non collegata</div>
385
+              </div>
386
+            </div>
193 387
           @endif
194
-        </div>
195
-        @if($ordine->pagamenti->count() > 0)
196
-        <div class="mb-3">
197
-          <h6 class="fw-bold mb-2">Pagamenti</h6>
198
-          <ul class="list-unstyled mb-0">
199
-            @foreach($ordine->pagamenti as $pagamento)
200
-              <!-- <li>
201
-                <span>
202
-                  <i class="bx bx-credit-card me-1"></i>
203
-                  {{ $pagamento->metodo_pagamento->nome ?? 'Pagamento' }}:
204
-                  <strong>€ {{ number_format($pagamento->importo, 2, ',', '.') }}</strong>
205
-                  <small class="text-muted">({{ $pagamento->stato ?? '' }})</small>
206
-                  <i class="bx bx-right-arrow-alt"></i>
207
-                </span>
208
-              </li> -->
209
-              <li class="report-list-item-li p-2 rounded-3 transition-all duration-300">
210
-              <div class="report-list-item rounded-2">
211
-                <div class="d-flex align-items-center">
212
-                  <div class="report-list-icon shadow-xs me-4">
213
-                  <span class="fs-4 badge rounded-2 bg-label-secondary p-2 ">
214
-                    @switch($pagamento->metodo_pagamento->tipo)
215
-                    @case('carta_di_credito')
216
-                      <i class="bx bx-credit-card"></i>
217
-                      @break
218
-                    @case('carta_di_debito')
219
-                    
220
-                      <i class="bx bx-credit-card"></i>
221
-                      @break
222
-                    @case('bonifico')
223
-                      <i class="bx bx-transfer"></i>
224
-                      @break
225
-                    @case('paypal')
226
-                      <i class="bx bx-paypal"></i>
227
-                      @break
228
-                    @case('stripe')
229
-                      <i class="bx bx-credit-card"></i>
230
-                      @break
231
-                    @case('contanti')
232
-                      <i class="bx bx-money"></i>
233
-                      @break
234
-                    @case('credito')
235
-                      <i class="bx bx-wallet"></i>
236
-                      @break
237
-                    @case('apple_pay')
238
-                      <i class="bx bx-mobile"></i>
239
-                      @break
240
-                    @case('google_pay')
241
-                      <i class="bx bx-mobile"></i>
242
-                      @break
243
-                    @case('cupon')
244
-                      <i class="bx bx-purchase-tag"></i>
245
-                      @break
246
-                    @case('segresta_wallet')
247
-                      <i class="bx bx-wallet"></i>
248
-                      @break
249
-                    @case('pos')
250
-                      <i class="bx bx-credit-card"></i>
251
-                      @break
252
-                    @default
253
-                      <i class="bx bx-credit-card"></i>
254
-                      @break
255
-                    @endswitch
256
-                    </span>
257
-                  </div>
258
-                  <div class="d-flex justify-content-between align-items-center w-100 flex-wrap gap-2">
259
-                    <div class="d-flex flex-column">
260
-                      <span>{{ $pagamento->metodo_pagamento->nome ?? 'Pagamento' }}</span>
261
-                      <small class="text-success">{!! view('prenotazione._partials.stato-prenotazione', ['stato' => $ordine->stato]) !!}</small>
262
-                    </div>
263
-                    <h5 class="mb-0" id="importo-totale">€ {{ number_format($pagamento->importo, 2, ',', '.') }}</h5>
264
-                  </div>
388
+
389
+          @forelse($ordine->pagamenti as $pagamento)
390
+            <a href="{{ route('pagamento.show', ['pagamento_id' => $pagamento->id]) }}" class="or-show-link-card text-body text-decoration-none">
391
+              <div class="or-show-link-card__icon">
392
+                <i class="bx {{ $iconePagamento[$pagamento->metodo_pagamento->tipo ?? ''] ?? 'bx-credit-card' }}"></i>
393
+              </div>
394
+              <div class="or-show-link-card__body">
395
+                <div class="or-show-link-card__label">Pagamento #{{ $pagamento->id }}</div>
396
+                <div class="or-show-link-card__title">
397
+                  {{ $pagamento->metodo_pagamento->nome ?? 'Pagamento' }}
398
+                  · € {{ number_format((float) $pagamento->importo, 2, ',', '.') }}
399
+                </div>
400
+                <div class="or-show-link-card__subtitle">
401
+                  @include('prenotazione._partials.stato-prenotazione', ['stato' => $pagamento->stato])
265 402
                 </div>
266 403
               </div>
267
-              </li>
268
-            @endforeach
269
-          </ul>
270
-        </div>
271
-        @endif
272
-        @if(isset($ordine->cliente) && $ordine->cliente)
273
-        <div class="mb-3">
274
-          <h6 class="fw-bold mb-2">Cliente</h6>
275
-          <div><i class="bx bx-user"></i> {{ $ordine->cliente->nome ?? '' }} {{ $ordine->cliente->cognome ?? '' }}</div>
404
+              <i class="bx bx-chevron-right text-muted"></i>
405
+            </a>
406
+          @empty
407
+            <div class="or-show-link-card or-show-link-card--empty">
408
+              <div class="or-show-link-card__icon"><i class="bx bx-money"></i></div>
409
+              <div class="or-show-link-card__body">
410
+                <div class="or-show-link-card__label">Pagamento</div>
411
+                <div class="or-show-link-card__title text-muted">Nessun pagamento</div>
412
+              </div>
413
+            </div>
414
+          @endforelse
276 415
         </div>
277
-        @endif
278
-        <!-- Puoi aggiungere qui ulteriori entità correlate -->
279 416
       </div>
280 417
     </div>
281 418
   </div>
282 419
 </div>
283
-
284
-<div class="modal fade" id="basicModal" tabindex="-1" aria-hidden="true">
285
-            <div class="modal-dialog" role="document">
286
-              <div class="modal-content">
287
-                <div class="modal-header">
288
-                  <h5 class="modal-title" id="exampleModalLabel1">Modal title</h5>
289
-                  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
290
-                </div>
291
-                <div class="modal-body">
292
-                  <div class="row">
293
-                    <div class="col mb-6">
294
-                      <label for="nameBasic" class="form-label">Name</label>
295
-                      <input type="text" id="nameBasic" class="form-control" placeholder="Enter Name">
296
-                    </div>
297
-                  </div>
298
-                  <div class="row g-6">
299
-                    <div class="col mb-0">
300
-                      <label for="emailBasic" class="form-label">Email</label>
301
-                      <input type="email" id="emailBasic" class="form-control" placeholder="xxxx@xxx.xx">
302
-                    </div>
303
-                    <div class="col mb-0">
304
-                      <label for="dobBasic" class="form-label">DOB</label>
305
-                      <input type="date" id="dobBasic" class="form-control">
306
-                    </div>
307
-                  </div>
308
-                </div>
309
-                <div class="modal-footer">
310
-                  <button type="button" class="btn btn-label-secondary" data-bs-dismiss="modal">Close</button>
311
-                  <button type="button" class="btn btn-primary">Save changes</button>
312
-                </div>
313
-              </div>
314
-            </div>
315
-          </div>
316
-
317
-@endsection
318
-
319
-@section('page-script')
320
-
321
-<script>
322
-    document.addEventListener('DOMContentLoaded', function() {
323
-
324
-        function verificaTotale() {
325
-            $.ajax({
326
-                url: "{{ route('carrello.totale') }}",
327
-                type: "GET",
328
-                data: {
329
-                    dispositivo_id: "{{ $ordine->dispositivo_id }}",
330
-                    attivita_id: "{{ $ordine->attivita_id }}",
331
-                    ordine_id: "{{ $ordine->id }}",
332
-                },
333
-                success: function(response){
334
-                    // console.log(response['totale']);
335
-                    // totale_pagamenti = parseFloat(response['totale']);
336
-                    // Normalizza entrambi i totali come numeri decimali con due cifre dopo la virgola (es: "00.00")
337
-                    var totaleCarrello = parseFloat(response['totale'] || 0).toFixed(2);
338
-                    var totaleRigheOrdine = parseFloat("{{ number_format($ordine->righe_ordine->sum('prezzo'), 2, '.', '') }}").toFixed(2);
339
-                    // alert([totaleCarrello , totaleRigheOrdine , (totaleCarrello !== totaleRigheOrdine)]);
340
-                    if (totaleCarrello !== totaleRigheOrdine) {
341
-                        // alert("Il totale del carrello è diverso dal totale del pagamento");
342
-                        window.location.reload();
343
-                    }
344
-                    // alert("Il totale del carrello è uguale al totale del pagamento");
345
-                },
346
-                error: function(xhr, status, error){
347
-                    console.log(xhr.responseText);
348
-                }
349
-            });
350
-        }
351
-
352
-        setInterval(verificaTotale, 1500); // Esegui la funzione ogni 1500ms (1.5 secondi)
353
-    });
354
-</script>
355
-
356 420
 @endsection

+ 87
- 6
resources/views/punto_vendita/cassa/_partials/carrello/pagamento/checkout.blade.php Ver fichero

@@ -161,6 +161,9 @@ $campiOrdineVisibili = collect($campiOrdine)
161 161
                     @if($metodo->tipo == MetodoPagamento::SEGRESTA_WALLET)
162 162
                       class="form-check-input segrestaWalletInput"
163 163
                       data-tipo="{{ MetodoPagamento::SEGRESTA_WALLET }}"
164
+                    @elseif($metodo->tipo == MetodoPagamento::CUPON)
165
+                      class="form-check-input cuponInput"
166
+                      data-tipo="{{ MetodoPagamento::CUPON }}"
164 167
                     @else
165 168
                       class="form-check-input"
166 169
                     @endif
@@ -185,6 +188,26 @@ $campiOrdineVisibili = collect($campiOrdine)
185 188
                     Scansiona un braccialetto NFC valido per pagare con Segresta Wallet.
186 189
                   </span>
187 190
                 @endif
191
+                @if($metodo->tipo == MetodoPagamento::CUPON)
192
+                  <div class="mt-2 p-3 border rounded bg-lighter" id="cuponAlert" style="display: none;">
193
+                    <label class="form-label small fw-medium mb-1" for="cuponCode">Codice coupon</label>
194
+                    <div class="input-group input-group-sm">
195
+                      <input type="text" class="form-control" id="cuponCode" name="cupon_codice" placeholder="Inserisci codice..." autocomplete="off">
196
+                      <button type="button" class="btn btn-outline-primary" id="btnCheckCupon">
197
+                        <i class="bx bx-search-alt"></i>
198
+                      </button>
199
+                    </div>
200
+                    <div id="cuponFeedback" class="mt-2" style="display: none;">
201
+                      <div id="cuponCheckMessage" class="small fw-medium mb-1"></div>
202
+                      <div class="d-flex flex-wrap gap-2 small text-muted">
203
+                        <span id="cuponImporto" style="display: none;"></span>
204
+                        <span id="cuponNominativo" style="display: none;"></span>
205
+                        <span id="cuponValiditaDa" style="display: none;"></span>
206
+                        <span id="cuponValiditaA" style="display: none;"></span>
207
+                      </div>
208
+                    </div>
209
+                  </div>
210
+                @endif
188 211
               </div>
189 212
             </div>
190 213
           @endforeach
@@ -219,6 +242,21 @@ $(document).ready(function(){
219 242
       checkUX($(this));
220 243
 
221 244
   });
245
+
246
+  $('#cuponCode').on('input', function(){
247
+    var val = $(this).val().trim();
248
+    if(val.length >= 3) {
249
+      checkCupon(val);
250
+    } else {
251
+      resetCuponFeedback();
252
+      $('button[type="submit"]').prop('disabled', true);
253
+    }
254
+  });
255
+
256
+  $('#btnCheckCupon').on('click', function(){
257
+    var val = $('#cuponCode').val().trim();
258
+    if(val.length > 0) checkCupon(val);
259
+  });
222 260
 });
223 261
 
224 262
 function checkUX(input){
@@ -227,16 +265,21 @@ function checkUX(input){
227 265
       // 
228 266
 
229 267
 
268
+      $('#segrestaWalletAlertToScan').hide();
269
+      $('#cuponAlert').hide();
270
+      resetCuponFeedback();
271
+
230 272
       if(input.data('tipo') == "{{ MetodoPagamento::SEGRESTA_WALLET }}"){
231 273
         $('#segrestaWalletAlertToScan').show();
232 274
         $('button[type="submit"]').prop('disabled', true);
233 275
         scanningNfcRequest();
234
-      
235
-    }else{
236
-      $('#segrestaWalletAlertToScan').hide();
237
-      $('button[type="submit"]').prop('disabled', false);
238
-      ;
239
-    }
276
+      } else if(input.data('tipo') == "{{ MetodoPagamento::CUPON }}"){
277
+        $('#cuponAlert').show();
278
+        $('#cuponCode').val('');
279
+        $('button[type="submit"]').prop('disabled', true);
280
+      } else {
281
+        $('button[type="submit"]').prop('disabled', false);
282
+      }
240 283
   
241 284
 }
242 285
 
@@ -283,6 +326,44 @@ function bindCheckoutSpinner() {
283 326
   });
284 327
 }
285 328
 
329
+function resetCuponFeedback(){
330
+  $('#cuponFeedback').hide();
331
+  $('#cuponCheckMessage').text('').removeClass('text-success text-danger');
332
+  $('#cuponImporto, #cuponNominativo, #cuponValiditaDa, #cuponValiditaA').hide().text('');
333
+}
334
+
335
+function checkCupon(codice) {
336
+  resetCuponFeedback();
337
+  $.ajax({
338
+    url: "{{ route('cupon.check') }}",
339
+    type: 'POST',
340
+    data: {
341
+      cupon_codice: codice,
342
+      _token: "{{ csrf_token() }}",
343
+      ordine_id: "{{ $ordine->id }}"
344
+    },
345
+    success: function(response){
346
+      $('#cuponFeedback').show();
347
+      if(response.success){
348
+        $('#cuponCheckMessage').addClass('text-success').text(response.message);
349
+        if(response.importo) $('#cuponImporto').show().html('<i class="bx bx-euro"></i> '+response.importo);
350
+        if(response.nominativo) $('#cuponNominativo').show().html('<i class="bx bx-user"></i> '+response.nominativo);
351
+        if(response.validita_da) $('#cuponValiditaDa').show().html('<i class="bx bx-calendar"></i> da '+response.validita_da);
352
+        if(response.validita_a) $('#cuponValiditaA').show().html('<i class="bx bx-calendar-check"></i> a '+response.validita_a);
353
+        $('button[type="submit"]').prop('disabled', false);
354
+      } else {
355
+        $('#cuponCheckMessage').addClass('text-danger').text(response.message);
356
+        $('button[type="submit"]').prop('disabled', true);
357
+      }
358
+    },
359
+    error: function(){
360
+      $('#cuponFeedback').show();
361
+      $('#cuponCheckMessage').addClass('text-danger').text('Errore di connessione. Riprova.');
362
+      $('button[type="submit"]').prop('disabled', true);
363
+    }
364
+  });
365
+}
366
+
286 367
 /////////////////////// spostato in INDEX
287 368
 // let nfcAbortController = null;
288 369
 

+ 8
- 8
resources/views/punto_vendita/cassa/viste/catalogo/index.blade.php Ver fichero

@@ -117,7 +117,7 @@ $ordineCoperti = (string) ($infoOrdine['coperti'] ?? '');
117 117
           <a class="dropdown-item text-danger" href="javascript:void(0);" onclick="dissociaDispositivo()">
118 118
             <i class="bx bx-unlink me-2"></i>Dissocia dispositivo
119 119
           </a>
120
-        </div>
120
+    </div>
121 121
       </div>
122 122
 
123 123
       <!-- <a href="{{ route('punto-vendita.show', ['punto_vendita_id' => $punto_vendita->id , 'vista' => 'catalogo']) }}" class=" ms-2 px-3 py-1 alert text-bg-primary"> 
@@ -265,7 +265,7 @@ $ordineCoperti = (string) ($infoOrdine['coperti'] ?? '');
265 265
               @endforeach
266 266
             @endforeach
267 267
           </div>
268
-        </div>
268
+          </div>
269 269
         </div>
270 270
       </div>
271 271
     </section>
@@ -335,9 +335,9 @@ $ordineCoperti = (string) ($infoOrdine['coperti'] ?? '');
335 335
 
336 336
               </div>
337 337
               </div>
338
-            </div>
339
-          </div>
340
-          
338
+  </div>
339
+</div>
340
+
341 341
 <script>
342 342
   (function () {
343 343
     const KITCHEN_PAGE_SIZE = 10;
@@ -511,9 +511,9 @@ $ordineCoperti = (string) ($infoOrdine['coperti'] ?? '');
511 511
         if (isPreOrdine) {
512 512
           selectedKitchenLabel.textContent = 'Pre-ordine';
513 513
         } else {
514
-          const labelEl = selectedTab ? selectedTab.querySelector('.cassa-sb-kitchen-label') : null;
515
-          selectedKitchenLabel.textContent = labelEl ? labelEl.textContent.trim() : 'Tutte';
516
-        }
514
+        const labelEl = selectedTab ? selectedTab.querySelector('.cassa-sb-kitchen-label') : null;
515
+        selectedKitchenLabel.textContent = labelEl ? labelEl.textContent.trim() : 'Tutte';
516
+      }
517 517
       }
518 518
 
519 519
       if (isPreOrdine) {

Loading…
Cancelar
Guardar