2 Commits

Autor SHA1 Nachricht Datum
  marcofalabretti ffa8aefedd Dashboard cucina, fix UX carrello/cassa vor 1 Monat
  marcofalabretti 3800dc5644 Variante piatto con stampe vor 1 Monat
30 geänderte Dateien mit 2161 neuen und 279 gelöschten Zeilen
  1. 44
    6
      app/DataTables/CucinaDataTable.php
  2. 45
    7
      app/DataTables/PiattoDataTable.php
  3. 15
    12
      app/DataTables/RigaOrdineDataTable.php
  4. 139
    0
      app/DataTables/VariantePiattoDataTable.php
  5. 106
    0
      app/DataTables/VariantePiattoDataTableEditor.php
  6. 38
    1
      app/Http/Controllers/CarrelloController.php
  7. 39
    0
      app/Http/Controllers/CucinaController.php
  8. 18
    2
      app/Http/Controllers/PiattoController.php
  9. 207
    168
      app/Http/Controllers/PuntoVenditaController.php
  10. 108
    0
      app/Http/Controllers/VariantePiattoController.php
  11. 5
    1
      app/Models/AbstractModels/AbstractRigaOrdine.php
  12. 69
    0
      app/Models/AbstractModels/AbstractRigaOrdineHasVariante.php
  13. 11
    1
      app/Models/AbstractModels/AbstractVariantePiatto.php
  14. 10
    0
      app/Models/RigaOrdineHasVariante.php
  15. 197
    9
      app/Services/Carrello/CarrelloService.php
  16. 6
    1
      app/Services/Stampa/CreaComandaCucina.php
  17. 22
    1
      app/Services/Stampa/CreaScontrino.php
  18. 6
    0
      database/migrations/2026_06_20_143147_create_variantes_table.php
  19. 34
    0
      database/migrations/2026_06_21_223039_create_riga_ordine_has_variante_table.php
  20. 268
    0
      resources/views/cucina/dashboard.blade.php
  21. 9
    1
      resources/views/cucina/menu.blade.php
  22. 5
    8
      resources/views/piatto/datatable.blade.php
  23. 71
    12
      resources/views/punto_vendita/cassa/_partials/carrello/cmd_carrello.blade.php
  24. 150
    0
      resources/views/punto_vendita/cassa/_partials/carrello/item.blade.php
  25. 248
    5
      resources/views/punto_vendita/cassa/_partials/scripts.blade.php
  26. 187
    37
      resources/views/punto_vendita/cassa/index.blade.php
  27. 9
    0
      resources/views/variante_piatto/datatable.blade.php
  28. 55
    0
      resources/views/variante_piatto/datatable_script.blade.php
  29. 23
    0
      resources/views/variante_piatto/menu.blade.php
  30. 17
    7
      routes/web.php

+ 44
- 6
app/DataTables/CucinaDataTable.php Datei anzeigen

@@ -19,8 +19,20 @@ use Illuminate\Support\Facades\Session;
19 19
 
20 20
 class CucinaDataTable extends DataTable
21 21
 {
22
-    public function __construct(){
22
+    public bool $dashboard = false;
23
+
24
+    public ?int $attivita_id = null;
25
+
26
+    public function __construct()
27
+    {
23 28
         $this->dataTableVariable = 'dataTable_cucina';
29
+        $this->dashboard = request()->boolean('dashboard')
30
+            || request()->routeIs('cucina.dashboard');
31
+    }
32
+
33
+    protected function isDashboard(): bool
34
+    {
35
+        return $this->dashboard || request()->routeIs('cucina.dashboard');
24 36
     }
25 37
     /**
26 38
      * Build the DataTable class.
@@ -31,7 +43,7 @@ class CucinaDataTable extends DataTable
31 43
     {
32 44
         return (new EloquentDataTable($query))
33 45
             ->addColumn('action', function($entity){
34
-              return view('cucina.menu', ['entity' => $entity]);
46
+                return view('cucina.menu', ['entity' => $entity, 'dashboard' => $this->isDashboard()]);
35 47
             })
36 48
             ->addColumn('is_attiva_display', function($entity){
37 49
               return view('_partials.available', ['available' => $entity->is_attiva]);
@@ -79,19 +91,19 @@ class CucinaDataTable extends DataTable
79 91
      */
80 92
     public function html(): HtmlBuilder
81 93
     {
94
+      
82 95
         $buttons = [];
83 96
         if(Auth::user()->can('create-cucina')){
84 97
             array_push($buttons, Button::make('create')
85 98
             ->editor('editor')
86 99
             ->formTitle('Crea nuovo cucina')
87 100
             ->className('btn btn-sm btn-primary mb-4')
88
-            ->text('<i class="fas fa-plus"></i> Nuovo cucina'));
101
+            ->text('<i class="fas fa-plus"></i> Nuova cucina'));
89 102
         }
90 103
 
91
-        return $this->builder()
104
+        $builder = $this->builder()
92 105
                     ->setTableId($this->dataTableVariable)
93 106
                     ->columns($this->getColumns())
94
-                    ->minifiedAjax()
95 107
                     ->initComplete("function(settings, json){
96 108
                         initComplete_cucina();
97 109
                     }")
@@ -103,6 +115,7 @@ class CucinaDataTable extends DataTable
103 115
                     ->buttons($buttons)
104 116
                     ->editor(
105 117
                         Editor::make()
118
+                        ->ajax(route('cucina.store'))
106 119
                         ->fields([
107 120
                           Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
108 121
                             Fields\Text::make('colore')->label('Colore')->set('attr', ['type' => 'color']),
@@ -116,6 +129,15 @@ class CucinaDataTable extends DataTable
116 129
                     )
117 130
                     ->buttons($buttons)
118 131
                     ->orderBy(1);
132
+
133
+                    if ($this->isDashboard()) {
134
+                        $builder->minifiedAjax(route('cucina.index'), null, ['dashboard' => 1]);
135
+                    } else {
136
+                        $builder->minifiedAjax();
137
+                    }
138
+
139
+                    return $builder;
140
+                    
119 141
     }
120 142
 
121 143
     /**
@@ -123,7 +145,22 @@ class CucinaDataTable extends DataTable
123 145
      */
124 146
     public function getColumns(): array
125 147
     {
126
-        return [
148
+
149
+      $dashboard_columns = [
150
+        Column::make('id')->visible(false),
151
+        Column::make('is_attiva_display')->title('')->addClass('text-center')->responsivePriority(1),
152
+        Column::make('badge_colore')->title('Cucina')->addClass('text-left')->responsivePriority(1),
153
+        Column::computed('piatti_count')->title('Piatti')->addClass('text-center'),
154
+        Column::computed('action')
155
+        ->title('')
156
+        ->exportable(false)
157
+        ->printable(false)
158
+        ->width(60)
159
+        ->addClass('text-center')
160
+        ->responsivePriority(1),
161
+      ];
162
+
163
+      $columns = [
127 164
             Column::make('id')->visible(false),
128 165
             Column::make('is_attiva_display')->title('Disponibile')->addClass('text-center')->responsivePriority(1),
129 166
             // Column::make('nome'),
@@ -142,6 +179,7 @@ class CucinaDataTable extends DataTable
142 179
             ->addClass('text-center')
143 180
             ->responsivePriority(1),
144 181
         ];
182
+        return $this->isDashboard() ? $dashboard_columns : $columns;
145 183
     }
146 184
 
147 185
     /**

+ 45
- 7
app/DataTables/PiattoDataTable.php Datei anzeigen

@@ -20,9 +20,22 @@ use Illuminate\Support\Facades\Session;
20 20
 
21 21
 class PiattoDataTable extends DataTable
22 22
 {
23
+    public bool $dashboard = false;
24
+
25
+    public ?int $attivita_id = null;
26
+
27
+    public ?int $cucina_id = null;
28
+
23 29
     public function __construct()
24 30
     {
25 31
         $this->dataTableVariable = 'dataTable_piatto';
32
+        $this->dashboard = request()->boolean('dashboard')
33
+            || request()->routeIs('piatto.datatable');
34
+    }
35
+
36
+    protected function isDashboard(): bool
37
+    {
38
+        return $this->dashboard || request()->routeIs('piatto.datatable');
26 39
     }
27 40
     /**
28 41
      * Build the DataTable class.
@@ -96,7 +109,7 @@ class PiattoDataTable extends DataTable
96 109
                 ->text('<i class="fas fa-plus"></i> Nuovo piatto'));
97 110
         }
98 111
 
99
-        if (Auth::user()->can('view-cucina')) {
112
+        if (Auth::user()->can('view-cucina') && ! $this->isDashboard()) {
100 113
 
101 114
             array_push($buttons, 
102 115
             Button::raw()
@@ -107,17 +120,18 @@ class PiattoDataTable extends DataTable
107 120
         }
108 121
 
109 122
 
110
-        if (isset($this->cucina_id)) {
123
+        if (isset($this->cucina_id) && ! $this->isDashboard()) {
111 124
             array_push($buttons, Button::raw()
112 125
             ->formTitle('Visualizza tutti i piatti')
113 126
             ->className('btn btn-sm btn-primary ml-2 mb-4')
114 127
             ->action('GoToAllPiatti()')
115 128
             ->text('<i class="bx bx-dish"></i> Tutti i piatti'));
116 129
         }
117
-        return $this->builder()
130
+
131
+        $builder = $this->builder()
118 132
             ->setTableId($this->dataTableVariable)
119 133
             ->columns($this->getColumns())
120
-            ->minifiedAjax()
134
+            // ->minifiedAjax()
121 135
             ->orderBy(1)
122 136
             ->responsive()
123 137
             // ->searchable(true)
@@ -129,6 +143,7 @@ class PiattoDataTable extends DataTable
129 143
             // ->ajax(route('piatto.store'))
130 144
             ->editor(
131 145
                 Editor::make()
146
+                    ->ajax(route('piatto.store'))
132 147
                     ->fields([
133 148
                         Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
134 149
                         Fields\Text::make('nome')->label('Nome'),
@@ -149,6 +164,17 @@ class PiattoDataTable extends DataTable
149 164
             ->initComplete("function(settings, json){
150 165
                         initComplete_piatto();
151 166
                     }");
167
+
168
+                    if ($this->isDashboard()) {
169
+                        $builder->minifiedAjax(route('piatto.index'), null, array_filter([
170
+                            'dashboard' => 1,
171
+                            'cucina_id' => $this->cucina_id,
172
+                        ]));
173
+                    } else {
174
+                        $builder->minifiedAjax();
175
+                    }
176
+
177
+                    return $builder;
152 178
     }
153 179
 
154 180
     /**
@@ -156,6 +182,15 @@ class PiattoDataTable extends DataTable
156 182
      */
157 183
     public function getColumns(): array
158 184
     {
185
+        $dashboard_columns = [
186
+            Column::make('id')->visible(false),
187
+            Column::make('is_attivo_display')->title('')->addClass('text-center')->responsivePriority(1),
188
+            // Column::make('cucina_id')->data('cucina_id_display')->title('cucina')->addClass('text-center'),
189
+            Column::make('nome')->title('Nome')->searchable()->responsivePriority(1),
190
+            Column::make('prezzo')->data('prezzo_display')->title('Prezzo')->addClass('text-center'),
191
+            Column::computed('action')->title('')->width('10%')->addClass('text-center')->responsivePriority(1),
192
+        ];
193
+
159 194
         $columns = [
160 195
             Column::make('id')->title('ID')->width('10%')->visible(false),
161 196
             Column::make('is_attivo')->data('is_attivo_display')->title('Disponibile')->width('10%')->responsivePriority(1),
@@ -171,13 +206,16 @@ class PiattoDataTable extends DataTable
171 206
             // Column::computed('cucina_id')->data('cucina_id_display')->title('Cucina')->addClass('text-center')->responsivePriority(2), // icona in tabella
172 207
             Column::make('allergeni')->title('Allergeni')->visible(false), // valore grezzo per l'editor (array ID)
173 208
             Column::make('allergeni')->data('allergeni_display')->title('Allergeni')->visible(true),
174
-            Column::make('bacheca_id')->data('bacheca_id_display')->title('Bacheca')->addClass('text-center'), // icona in tabella
175
-            Column::make('in_evidenza')->data('in_evidenza_display')->title('In evidenza')->addClass('text-center'), // icona in tabella
209
+            // Column::make('bacheca_id')->data('bacheca_id_display')->title('Bacheca')->addClass('text-center'), // icona in tabella
210
+            // Column::make('in_evidenza')->data('in_evidenza_display')->title('In evidenza')->addClass('text-center'), // icona in tabella
176 211
             Column::computed('action')->title('')->width('10%')->addClass('text-center')->responsivePriority(1),
177
-
178 212
         ]);
179 213
         // dd($columns);
180 214
 
215
+        if ($this->isDashboard()) {
216
+            return $dashboard_columns;
217
+        }
218
+
181 219
         return $columns;
182 220
     }
183 221
 

+ 15
- 12
app/DataTables/RigaOrdineDataTable.php Datei anzeigen

@@ -70,18 +70,13 @@ class RigaOrdineDataTable extends DataTable
70 70
             ->addColumn('vista_catalogo', function ($query) {
71 71
                 return view('punto_vendita.cassa.viste.catalogo._partials.carrello-item', ['riga_ordine' => $query]);
72 72
             })
73
+            ->addColumn('colonna_action', function ($query) {
74
+                return view('punto_vendita.cassa._partials.carrello.cmd_carrello', ['cmd' => 'colonna_action', 'piatto_id' => $query->piatto_id , 'riga_ordine_id' => $query->id]);
75
+            })->addColumn('carrello_item', function ($query) {
76
+                return view('punto_vendita.cassa._partials.carrello.item', ['riga_ordine' => $query, 'piatto_id' => $query->piatto_id , 'riga_ordine_id' => $query->id]);
77
+            })
73 78
             ->setRowId('id')
74
-            // ->rawColumns([
75
-            //     'aumenta',
76
-            //     'diminuisci',
77
-            //     'elimina',
78
-            //     'riga_ordine',
79
-            //     'note_display',
80
-            //     'quantita_display',
81
-            //     'piatto_display',
82
-            //     'menu_display',
83
-            // ]);
84
-            ;
79
+            ->rawColumns(['carrello_item']);
85 80
     }
86 81
 
87 82
     /**
@@ -101,6 +96,7 @@ class RigaOrdineDataTable extends DataTable
101 96
     public function html(): HtmlBuilder
102 97
     {
103 98
         $buttons = [];
99
+        $ajaxUrl = request()->fullUrl();
104 100
         
105 101
             array_push($buttons, Button::raw('Azzerare carrello')
106 102
                 ->className('btn btn-sm btn-danger mb-4')
@@ -112,7 +108,9 @@ class RigaOrdineDataTable extends DataTable
112 108
         return $this->builder()
113 109
                     ->setTableId($this->dataTableVariable)
114 110
                     ->columns($this->getColumns())
115
-                    ->minifiedAjax()
111
+                    // URL esplicita: mantiene query string (es. punto_vendita_id)
112
+                    // evitando redirect del controller show durante le richieste draw.
113
+                    ->minifiedAjax($ajaxUrl)
116 114
                     ->language(asset('assets/Italian.json'))
117 115
                     // ->dom(count($buttons) == 0 ? 'rtip' : 'Brtip')
118 116
                     ->dom('rtip')
@@ -138,6 +136,10 @@ class RigaOrdineDataTable extends DataTable
138 136
      */
139 137
     public function getColumns(): array
140 138
     {
139
+        return [
140
+            Column::make('id')->visible(false),
141
+            Column::make('carrello_item')->title('')->searchable(true)->data('carrello_item')->addClass('text-start col-5 col-sm-5 col-md-5 col-lg-5 col-xl-5 col-xxl-5'),
142
+        ];
141 143
  
142 144
         if($this->vista == 'catalogo'){
143 145
             return [
@@ -156,6 +158,7 @@ class RigaOrdineDataTable extends DataTable
156 158
             Column::make('prezzo')->title('Prezzo')->data('prezzo_display')->addClass('text-center'),
157 159
             // Column::make('note')->title('Note')->addClass('text-center')->width('10%')->visible(false),
158 160
             // Column::make('elimina')->title('')->addClass('text-center')->width('10%'),
161
+            // Column::make('colonna_action')->title('')->addClass('text-center')->width('10%')->data('colonna_action'),
159 162
             Column::computed('menu')->title('')->addClass('text-center details-control')->width('10%')->data('menu_display'),
160 163
         ];
161 164
     }

+ 139
- 0
app/DataTables/VariantePiattoDataTable.php Datei anzeigen

@@ -0,0 +1,139 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\VariantePiatto;
6
+use App\Models\Piatto;
7
+use App\Models\Cucina;
8
+use Illuminate\Database\Eloquent\Builder as QueryBuilder;
9
+use Yajra\DataTables\EloquentDataTable;
10
+use Yajra\DataTables\Html\Builder as HtmlBuilder;
11
+use Yajra\DataTables\Html\Button;
12
+use Yajra\DataTables\Html\Column;
13
+use Yajra\DataTables\Html\Editor\Editor;
14
+use Yajra\DataTables\Html\Editor\Fields;
15
+use Yajra\DataTables\Services\DataTable;
16
+use Illuminate\Support\Facades\Auth;
17
+
18
+class VariantePiattoDataTable extends DataTable
19
+{
20
+    public bool $dashboard = false;
21
+
22
+    public ?int $attivita_id = null;
23
+
24
+    public ?int $cucina_id = null;
25
+
26
+    public function __construct()
27
+    {
28
+        $this->dataTableVariable = 'dataTable_variante_piatto';
29
+        $this->dashboard = request()->boolean('dashboard')
30
+            || request()->routeIs('variante-piatto.datatable');
31
+    }
32
+
33
+    protected function isDashboard(): bool
34
+    {
35
+        return $this->dashboard || request()->routeIs('variante-piatto.datatable');
36
+    }
37
+    /**
38
+     * Build the DataTable class.
39
+     *
40
+     * @param QueryBuilder<VariantePiatto> $query Results from query() method.
41
+     */
42
+    public function dataTable(QueryBuilder $query): EloquentDataTable
43
+    {
44
+        return (new EloquentDataTable($query))
45
+            ->addColumn('action', function($entity){
46
+                return view('variante_piatto.menu', ['entity' => $entity, 'dashboard' => $this->isDashboard()]);
47
+            })
48
+            ->addColumn('prezzo_display', function($entity){
49
+                return '€ ' . number_format($entity->prezzo, 2, ',', '.');
50
+            })
51
+            ->setRowId('id');
52
+    }
53
+
54
+    /**
55
+     * Get the query source of dataTable.
56
+     *
57
+     * @return QueryBuilder<VariantePiatto>
58
+     */
59
+    public function query(VariantePiatto $model): QueryBuilder
60
+    {
61
+        $query = $model->newQuery()->where('attivita_id', $this->attivita_id);
62
+        if (isset($this->cucina_id)) {
63
+            $query->where('cucina_id', $this->cucina_id);
64
+        }
65
+        // if (isset($this->cucina_id)) {
66
+        //     $query->whereHas('piatto', function ($q) {
67
+        //         $q->where('cucina_id', $this->cucina_id);
68
+        //     });
69
+        // }
70
+
71
+        return $query;
72
+    }
73
+
74
+    /**
75
+     * Optional method if you want to use the html builder.
76
+     */
77
+    public function html(): HtmlBuilder
78
+    {
79
+        $buttons = [];
80
+        if (Auth::user()->can('create-variante-piatto')) {
81
+            array_push($buttons, Button::make('create')
82
+                ->editor('editor')
83
+                ->formTitle('Crea nuova variante piatto')
84
+                ->className('btn btn-sm btn-primary mb-4')
85
+                ->text('<i class="fas fa-plus"></i> Nuova variante'));
86
+        }
87
+        $builder = $this->builder()
88
+                    ->setTableId($this->dataTableVariable)
89
+                    ->columns($this->getColumns())
90
+                    ->orderBy(1)
91
+                    ->responsive()
92
+                    ->editor(Editor::make()
93
+                        ->ajax(route('variante-piatto.store'))
94
+                        ->fields([
95
+                            Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
96
+                            Fields\Text::make('prezzo')->label('Prezzo'),
97
+                            Fields\Text::make('label')->label('Nome'),
98
+                            Fields\Select2::make('piatto_id')->label('Piatto')->options(Piatto::where('attivita_id', $this->attivita_id)->pluck('id', 'nome')),
99
+                            Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::where('attivita_id', $this->attivita_id)->pluck('id', 'nome')),
100
+                        ])
101
+                    )
102
+                    ->language(asset('assets/Italian.json'))
103
+                    ->dom(count($buttons) == 0 ? 'rtip' : 'Bfrtip')
104
+                    ->selectStyleSingle()
105
+                    ->buttons($buttons);
106
+
107
+        if ($this->isDashboard()) {
108
+            $builder->minifiedAjax(route('variante-piatto.index'), null, array_filter([
109
+                'dashboard' => 1,
110
+                'cucina_id' => $this->cucina_id,
111
+            ]));
112
+        } else {
113
+            $builder->minifiedAjax();
114
+        }
115
+
116
+        return $builder;
117
+    }
118
+
119
+    /**
120
+     * Get the dataTable columns definition.
121
+     */
122
+    public function getColumns(): array
123
+    {
124
+        return [
125
+            Column::make('id')->visible(false),
126
+            Column::make('label')->title('Nome')->searchable()->responsivePriority(1),
127
+            Column::make('prezzo')->data('prezzo_display')->title('Prezzo')->addClass('text-center'),
128
+            Column::computed('action')->title('')->width('10%')->addClass('text-center')->responsivePriority(1),
129
+        ];
130
+    }
131
+
132
+    /**
133
+     * Get the filename for export.
134
+     */
135
+    protected function filename(): string
136
+    {
137
+        return 'VariantePiatto_' . date('YmdHis');
138
+    }
139
+}

+ 106
- 0
app/DataTables/VariantePiattoDataTableEditor.php Datei anzeigen

@@ -0,0 +1,106 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\VariantePiatto;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Illuminate\Validation\Rule;
8
+use Yajra\DataTables\DataTablesEditor;
9
+use Illuminate\Http\Request;
10
+use Illuminate\Validation\ValidationException;
11
+use Storage;
12
+use Illuminate\Support\Str;
13
+
14
+class VariantePiattoDataTableEditor extends DataTablesEditor
15
+{
16
+  protected $model = VariantePiatto::class;
17
+  // protected $uploadDir = '';
18
+  // protected $disk = 'modelliRicevute';
19
+
20
+  protected $messages = [
21
+    'label.required' => 'Il nome è richiesto',
22
+    'prezzo.required' => 'Il prezzo è richiesto',
23
+    'is_attivo.required' => 'Indicare una delle due opzioni',
24
+    'piatto_id.required' => 'Il piatto è richiesto',
25
+    'cucina_id.required' => 'La cucina è richiesta',
26
+    'attivita_id.required' => 'L\'attività è richiesta',
27
+    'attivita_id.exists' => 'L\'attività non è valida',
28
+    'piatto_id.exists' => 'Il piatto non è valido',
29
+    'cucina_id.exists' => 'La cucina non è valida',
30
+  ];
31
+
32
+  /**
33
+  * Get create action validation rules.
34
+  *
35
+  * @return array
36
+  */
37
+  public function createRules(): array
38
+  {
39
+    return [
40
+      'label'  => 'required',
41
+      'attivita_id' => 'required|exists:attivita,id',
42
+      'prezzo' => 'required',
43
+      'is_attivo' => 'boolean',
44
+      'piatto_id' => 'nullable|exists:piatto,id',
45
+      'cucina_id' => 'required|exists:cucina,id',
46
+    ];
47
+  }
48
+
49
+  public function createMessages(): array{
50
+    return $this->messages;
51
+  }
52
+
53
+  /**
54
+  * Get edit action validation rules.
55
+  *
56
+  * @param Model $model
57
+  * @return array
58
+  */
59
+  public function editRules(Model $model): array
60
+  {
61
+    return [
62
+      'label'  => 'required',
63
+      'attivita_id' => 'required|exists:attivita,id',
64
+      'prezzo' => 'required',
65
+      'is_attivo' => 'boolean',
66
+      'piatto_id' => 'nullable|exists:piatto,id',
67
+      'cucina_id' => 'required|exists:cucina,id',
68
+    ];
69
+
70
+  }
71
+
72
+  public function editMessages(): array{
73
+    return $this->messages;
74
+  }
75
+
76
+  /**
77
+  * Get remove action validation rules.
78
+  *
79
+  * @param Model $model
80
+  * @return array
81
+  */
82
+  public function removeRules(Model $model): array
83
+  {
84
+    return [];
85
+  }
86
+
87
+  public function creating(Model $model, array $data): array
88
+  {
89
+    // $model->roles()->sync([$data['ruolo_id']]);
90
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
91
+    return $data;
92
+  }
93
+
94
+  public function updating(Model $model, array $data): array
95
+  {
96
+    // dd($data['ruolo']);
97
+    // $model->roles()->sync([$data['ruolo_id']]);
98
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
99
+    return $data;
100
+  }
101
+  public function messages(): array
102
+  {
103
+    return $this->messages;
104
+  }
105
+
106
+}

+ 38
- 1
app/Http/Controllers/CarrelloController.php Datei anzeigen

@@ -52,7 +52,7 @@ class CarrelloController extends Controller
52 52
             'attivita_id' => 'nullable|integer|exists:attivita,id',
53 53
         ]);
54 54
        
55
-       $result = $this->carrelloService->aumentaQuantita($request->dispositivo_id, $request->attivita_id, $request->ordine_id, $request->piatto_id);
55
+       $result = $this->carrelloService->aumentaQuantita($request->dispositivo_id, $request->attivita_id, $request->ordine_id, $request->piatto_id, $request->riga_ordine_id);
56 56
        $carrello = $result['ordine'];
57 57
        $riga = $result['riga'];
58 58
 
@@ -188,6 +188,43 @@ class CarrelloController extends Controller
188 188
         // ]);
189 189
     }
190 190
 
191
+    public function aggiungi_variante(Request $request){
192
+        $request->validate([
193
+            'tipo' => 'required|string|in:singolo,tutti',
194
+            'piatto_id' => 'required|integer|exists:piatto,id',
195
+            'riga_ordine_id' => 'required|integer|exists:riga_ordine,id',
196
+            'variante_id' => 'nullable|integer|exists:variante_piatto,id',
197
+            'nota' => 'nullable|string',
198
+        ]);
199
+        // dd($request->all());
200
+        $request->nota = null;
201
+        $result = null;
202
+        if($request->tipo == 'singolo'){
203
+            $result = $this->carrelloService->aggiungiVarianteSingoloPiatto($request->piatto_id, $request->riga_ordine_id, $request->variante_id, $request->nota);
204
+            
205
+        }elseif($request->tipo == 'tutti'){
206
+            $result = $this->carrelloService->aggiungiVarianteTuttiPiatto($request->piatto_id, $request->riga_ordine_id, $request->variante_id, $request->nota);
207
+        }else{
208
+
209
+            return response()->json([
210
+                'success' => false,
211
+                'message' => 'Tipo di variante non valido.',
212
+                'data' => null,
213
+            ]);
214
+        };
215
+
216
+        return $result;
217
+    }
218
+
219
+    public function elimina_variante(Request $request){
220
+        $request->validate([
221
+            'riga_ordine_id' => 'required|integer|exists:riga_ordine,id',
222
+            'variante_id' => 'required|integer|exists:variante_piatto,id',
223
+        ]);
224
+        $result = $this->carrelloService->eliminaVariante($request->riga_ordine_id, $request->variante_id);
225
+        return response()->json($result);
226
+    }
227
+
191 228
     public function azzera(Request $request){
192 229
         $request->validate([
193 230
             'ordine_id' => 'required|integer|exists:ordine,id',

+ 39
- 0
app/Http/Controllers/CucinaController.php Datei anzeigen

@@ -31,6 +31,11 @@ class CucinaController extends Controller
31 31
     public function index(CucinaDataTable $dataTable)
32 32
     {
33 33
         $dataTable->attivita_id = Session::get('attivita_attuale');
34
+
35
+        if (request()->boolean('dashboard')) {
36
+            $dataTable->dashboard = true;
37
+        }
38
+
34 39
         return $dataTable->render('cucina.index');
35 40
     }
36 41
 
@@ -55,4 +60,38 @@ class CucinaController extends Controller
55 60
     }
56 61
 
57 62
 
63
+    public function dashboard(CucinaDataTable $dataTable)
64
+    {
65
+        // if(request()->has('dashboard')){
66
+        //     $dataTable->dashboard = true;
67
+        // }
68
+        $dataTable->dashboard = true;
69
+        $dataTable->attivita_id = Session::get('attivita_attuale');
70
+        return $dataTable->render('cucina.dashboard');
71
+    }
72
+
73
+    // public function dashboard(Request $request)
74
+    // {
75
+    //     $attivita = \App\Models\Attivita::find(Session::get('attivita_attuale'));
76
+    //     if(!$attivita) return redirect()->route('attivita.index')->with('error', 'Attività non trovata');
77
+
78
+    //     $dataTable_cucina = app(\App\DataTables\CucinaDataTable::class);
79
+    //     $dataTable_cucina->attivita_id = $attivita->id;
80
+    //     $dataTable_cucina->dashboard = 1;
81
+
82
+    //     $dataTable_piatto = app(\App\DataTables\PiattoDataTable::class);
83
+    //     $dataTable_piatto->attivita_id = $attivita->id;
84
+    //     $dataTable_piatto->dashboard = true;
85
+
86
+    //     $dataTable_variante = app(\App\DataTables\VariantePiattoDataTable::class);
87
+    //     $dataTable_variante->attivita_id = $attivita->id;
88
+    //     $dataTable_variante->dashboard = true;
89
+
90
+    //     return view('cucina.dashboard')->with([
91
+    //         'dataTable_cucina' => $dataTable_cucina,
92
+    //         'dataTable_piatto' => $dataTable_piatto,
93
+    //         'dataTable_variante' => $dataTable_variante,
94
+    //     ]);
95
+    // }
96
+
58 97
 }

+ 18
- 2
app/Http/Controllers/PiattoController.php Datei anzeigen

@@ -29,15 +29,31 @@ class PiattoController extends Controller
29 29
     }
30 30
 
31 31
     public function index(PiattoDataTable $dataTable , Request $request){
32
+      $dataTable->attivita_id = Session::get('attivita_attuale');
33
+
34
+        if (request()->boolean('dashboard')) {
35
+            $dataTable->dashboard = true;
36
+        }
37
+
38
+        if (request()->has('cucina_id')) {
39
+            $dataTable->cucina_id = (int) request()->get('cucina_id');
40
+        }
41
+
42
+        return $dataTable->render('piatto.index');
43
+    }
44
+
45
+    public function datatable(PiattoDataTable $dataTable , Request $request){
32 46
       $dataTable->attivita_id = Session::get('attivita_attuale');
33 47
 
34 48
       if(request()->has('cucina_id')){
35 49
         $dataTable->cucina_id = request()->get('cucina_id');
36 50
       }
51
+      if(request()->has('dashboard')){
52
+        $dataTable->dashboard = true;
53
+      }
37 54
 
38
-        return $dataTable->render('piatto.index');
55
+        return $dataTable->render('piatto.datatable');
39 56
     }
40
-
41 57
     // public function datatable(PiattoDataTable $dataTable){
42 58
     //   $dataTable->menu_id = request()->get('menu_id');
43 59
     //   return $dataTable->render('piatto.datatable');

+ 207
- 168
app/Http/Controllers/PuntoVenditaController.php Datei anzeigen

@@ -2,29 +2,29 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
-use Illuminate\Http\Request;
6
-use App\Models\Cucina;
7
-use App\Models\Ordine;
8
-use App\Models\Dispositivo;
9
-use App\Models\Pagamento;
10 5
 use App\DataTables\PuntoVenditaDataTable;
11 6
 use App\DataTables\PuntoVenditaDataTableEditor;
12 7
 use App\DataTables\RigaOrdineDataTable;
8
+use App\Models\Dispositivo;
9
+use App\Models\Ordine;
10
+use App\Models\Pagamento;
11
+use Illuminate\Http\Request;
13 12
 use Illuminate\Support\Facades\Auth;
14
-use Illuminate\Support\Facades\Session;
15 13
 use Illuminate\Support\Facades\Cookie;
14
+use Illuminate\Support\Facades\Session;
16 15
 use Illuminate\Support\Str;
17 16
 
18 17
 class PuntoVenditaController extends Controller
19 18
 {
20
-    public static $permission_group = "Punto di vendita";
19
+    public static $permission_group = 'Punto di vendita';
20
+
21 21
     public static $permissions = [
22 22
         'view-punto_vendita' => 'Vedi',
23 23
         'create-punto_vendita' => 'Crea',
24 24
         'edit-punto_vendita' => 'Modifica',
25 25
         'delete-punto_vendita' => 'Elimina',
26 26
     ];
27
-    
27
+
28 28
     public static function middleware(): array
29 29
     {
30 30
         return [
@@ -32,7 +32,7 @@ class PuntoVenditaController extends Controller
32 32
             new Middleware('permission:create-punto_vendita|edit-punto_vendita|delete-punto_vendita', only: ['store', 'update', 'destroy', 'edit', 'associa_cucina']),
33 33
         ];
34 34
     }
35
-    
35
+
36 36
     public function index(PuntoVenditaDataTable $dataTable)
37 37
     {
38 38
         return $dataTable->render('punto_vendita.index');
@@ -44,7 +44,7 @@ class PuntoVenditaController extends Controller
44 44
             ->with(['attivita', 'hasCucine'])
45 45
             ->find($request->punto_vendita_id);
46 46
 
47
-        if (!$puntoVendita) {
47
+        if (! $puntoVendita) {
48 48
             return redirect()->route('punto-vendita.index')
49 49
                 ->with('error', 'Punto di vendita non trovato');
50 50
         }
@@ -56,10 +56,11 @@ class PuntoVenditaController extends Controller
56 56
     {
57 57
         $puntoVendita = Dispositivo::with(['hasCucine', 'attivita.cucine', 'attivita.stampanti'])
58 58
             ->find($request->get('punto_vendita_id'));
59
-        if(!$puntoVendita){
59
+        if (! $puntoVendita) {
60 60
             return redirect()->route('punto-vendita.index')
61
-            ->with('error', 'Punto di vendita non trovato');
61
+                ->with('error', 'Punto di vendita non trovato');
62 62
         }
63
+
63 64
         return view('punto_vendita.edit', ['puntoVendita' => $puntoVendita]);
64 65
     }
65 66
 
@@ -67,70 +68,76 @@ class PuntoVenditaController extends Controller
67 68
     {
68 69
         $puntoVendita = Dispositivo::find($request->get('punto_vendita_id'));
69 70
 
70
-        if(!$puntoVendita){
71
+        if (! $puntoVendita) {
71 72
             return redirect()->route('punto-vendita.index')
72
-            ->with('error', 'Punto di vendita non trovato');
73
+                ->with('error', 'Punto di vendita non trovato');
73 74
         }
74 75
 
75
-        if(Auth::user()->can('edit-punto_vendita')){
76
-
77
-        $validated = $request->validate([
78
-            'nome' => 'sometimes|required',
79
-            'tipo' => 'sometimes|required',
80
-            'attivita_id' => 'sometimes|required|exists:attivita,id',
81
-            'licenza' => 'sometimes|nullable',
82
-            'url_stampante' => 'sometimes|nullable',
83
-            'ubicazione' => 'sometimes|nullable',
84
-            'note' => 'sometimes|nullable',
85
-            'is_attivo' => 'boolean',
86
-            'pin_sblocco' => 'sometimes|nullable',
87
-            'data_apertura_dispositivo' => 'nullable|date',
88
-            'data_chiusura_dispositivo' => 'nullable|date',
89
-            'endpoint_id' => 'sometimes|nullable|exists:endpoint,id',
90
-            'info' => 'sometimes|nullable|json',
91
-        ],[
92
-            'nome.required' => 'Il nome è richiesto',
93
-            'tipo.required' => 'Il tipo è richiesto',
94
-            'attivita_id.required' => 'La attività è richiesta',
95
-            'licenza.required' => 'La licenza è richiesta',
96
-            'url_stampante.required' => 'L\'URL della stampante è richiesta',
97
-            'ubicazione.required' => 'L\'ubicazione è richiesta',
98
-            'pin_sblocco.required' => 'Il pin di sblocco è richiesto',
99
-            'data_apertura_dispositivo.required' => 'La data di apertura del dispositivo è richiesta',
100
-            'data_chiusura_dispositivo.required' => 'La data di chiusura del dispositivo è richiesta',
101
-            'data_apertura_dispositivo.date' => 'La data di apertura del dispositivo deve essere una data valida',
102
-            'data_chiusura_dispositivo.date' => 'La data di chiusura del dispositivo deve essere una data valida',
103
-            'is_attivo.boolean' => 'Indicare una delle due opzioni',
104
-            'pin_sblocco.string' => 'Il pin di sblocco deve essere una stringa',
105
-            'pin_sblocco.required' => 'Il pin di sblocco è richiesto',
106
-            'pin_sblocco.min' => 'Il pin di sblocco deve essere lungo almeno 4 caratteri',
107
-            'pin_sblocco.max' => 'Il pin di sblocco deve essere lungo al massimo 4 caratteri',
108
-            'pin_sblocco.regex' => 'Il pin di sblocco deve contenere solo numeri',
109
-            'pin_sblocco.unique' => 'Il pin di sblocco deve essere unico',
110
-            'info.json' => 'Il campo info deve essere un JSON valido',
111
-        ]);
76
+        if (Auth::user()->can('edit-punto_vendita')) {
77
+
78
+            $validated = $request->validate([
79
+                'nome' => 'sometimes|required',
80
+                'tipo' => 'sometimes|required',
81
+                'attivita_id' => 'sometimes|required|exists:attivita,id',
82
+                'licenza' => 'sometimes|nullable',
83
+                'url_stampante' => 'sometimes|nullable',
84
+                'ubicazione' => 'sometimes|nullable',
85
+                'note' => 'sometimes|nullable',
86
+                'is_attivo' => 'boolean',
87
+                'pin_sblocco' => 'sometimes|nullable',
88
+                'data_apertura_dispositivo' => 'nullable|date',
89
+                'data_chiusura_dispositivo' => 'nullable|date',
90
+                'endpoint_id' => 'sometimes|nullable|exists:endpoint,id',
91
+                'info' => 'sometimes|nullable|json',
92
+            ], [
93
+                'nome.required' => 'Il nome è richiesto',
94
+                'tipo.required' => 'Il tipo è richiesto',
95
+                'attivita_id.required' => 'La attività è richiesta',
96
+                'licenza.required' => 'La licenza è richiesta',
97
+                'url_stampante.required' => 'L\'URL della stampante è richiesta',
98
+                'ubicazione.required' => 'L\'ubicazione è richiesta',
99
+                'pin_sblocco.required' => 'Il pin di sblocco è richiesto',
100
+                'data_apertura_dispositivo.required' => 'La data di apertura del dispositivo è richiesta',
101
+                'data_chiusura_dispositivo.required' => 'La data di chiusura del dispositivo è richiesta',
102
+                'data_apertura_dispositivo.date' => 'La data di apertura del dispositivo deve essere una data valida',
103
+                'data_chiusura_dispositivo.date' => 'La data di chiusura del dispositivo deve essere una data valida',
104
+                'is_attivo.boolean' => 'Indicare una delle due opzioni',
105
+                'pin_sblocco.string' => 'Il pin di sblocco deve essere una stringa',
106
+                'pin_sblocco.required' => 'Il pin di sblocco è richiesto',
107
+                'pin_sblocco.min' => 'Il pin di sblocco deve essere lungo almeno 4 caratteri',
108
+                'pin_sblocco.max' => 'Il pin di sblocco deve essere lungo al massimo 4 caratteri',
109
+                'pin_sblocco.regex' => 'Il pin di sblocco deve contenere solo numeri',
110
+                'pin_sblocco.unique' => 'Il pin di sblocco deve essere unico',
111
+                'info.json' => 'Il campo info deve essere un JSON valido',
112
+            ]);
112 113
 
113
-        //Esempio di info:
114
-        // {
115
-        //     "campi_ordine" :{
116
-        //             "cliente" :{
117
-        //                 "label" : "Cliente",
118
-        //                 "placeholder" : "Inserisci il tup nome",
119
-        //                 "mostra" : true,
120
-        //                 "required" : false,
121
-        //                 "type" : "text",
122
-        //                 "stampa" : true,
123
-        //             }
124
-        //         }
125
-        // }
126
-        
127
-        if($request->has('info')){
128
-            $validated['info'] = json_decode($request->info, true);
129
-        }
114
+            // Esempio di info:
115
+            // {
116
+            //     "campi_ordine" :{
117
+            //             "cliente" :{
118
+            //                 "label" : "Cliente",
119
+            //                 "placeholder" : "Inserisci il tup nome",
120
+            //                 "mostra" : true,
121
+            //                 "required" : false,
122
+            //                 "type" : "text",
123
+            //                 "stampa" : true,
124
+            //             }
125
+            //         }
126
+            // }
127
+
128
+            if ($request->has('info')) {
129
+                $validated['info'] = json_decode($request->info, true);
130
+            }
131
+            if ($request->has('url_stampante')) {
132
+                $validated['endpoint_id'] = Dispositivo::where('id', $validated['url_stampante'])
133
+                    ->where('tipo', Dispositivo::STAMPANTE)->first()->endpoint_id ?? null;
134
+
135
+            }
130 136
 
131 137
             $puntoVendita->update($validated);
138
+
132 139
             return response()->json(['success' => true, 'message' => 'Punto di vendita aggiornato con successo']);
133
-        }else{
140
+        } else {
134 141
             return response()->json(['success' => false, 'message' => 'Non hai il permesso di accedere a questo punto di vendita']);
135 142
         }
136 143
     }
@@ -138,16 +145,16 @@ class PuntoVenditaController extends Controller
138 145
     public function associa_cucina(Request $request)
139 146
     {
140 147
         $puntoVendita = Dispositivo::find($request->get('punto_vendita_id'));
141
-        if(!$puntoVendita){
148
+        if (! $puntoVendita) {
142 149
             return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
143 150
         }
144 151
 
145
-        if(Auth::user()->can('edit-punto_vendita')){
146
-        $cucine_ids = $request->get('cucine_ids');
147
-        $puntoVendita->hasCucine()->sync($cucine_ids);
152
+        if (Auth::user()->can('edit-punto_vendita')) {
153
+            $cucine_ids = $request->get('cucine_ids');
154
+            $puntoVendita->hasCucine()->sync($cucine_ids);
148 155
 
149
-        return response()->json(['success' => true, 'message' => 'Cucine associate con successo']);
150
-        }else{
156
+            return response()->json(['success' => true, 'message' => 'Cucine associate con successo']);
157
+        } else {
151 158
             return response()->json(['success' => false, 'message' => 'Non hai il permesso di accedere a questo punto di vendita']);
152 159
         }
153 160
     }
@@ -156,86 +163,115 @@ class PuntoVenditaController extends Controller
156 163
     {
157 164
         $request = request();
158 165
         $input = $request->all();
159
-        if($request->has('action')){
160
-            switch($input['action']){
166
+        if ($request->has('action')) {
167
+            switch ($input['action']) {
161 168
                 case 'create':
162
-                    if(!Auth::user()->can('create-punto_vendita')) return;
169
+                    if (! Auth::user()->can('create-punto_vendita')) {
170
+                        return;
171
+                    }
163 172
                     break;
164 173
                 case 'edit':
165
-                    if(!Auth::user()->can('edit-punto_vendita')) return;
174
+                    if (! Auth::user()->can('edit-punto_vendita')) {
175
+                        return;
176
+                    }
166 177
                     break;
167 178
                 case 'remove':
168
-                    if(!Auth::user()->can('delete-punto_vendita')) return;
179
+                    if (! Auth::user()->can('delete-punto_vendita')) {
180
+                        return;
181
+                    }
169 182
                     break;
170 183
             }
171 184
         }
185
+
172 186
         return $editor->process($request);
173 187
     }
174 188
 
175 189
     public function show(Request $request, RigaOrdineDataTable $dataTable)
176 190
     {
177
-        if(!Auth::user()->can('view-punto_vendita')){
191
+        $isDataTableDrawRequest = $request->has('draw');
192
+
193
+        if (! Auth::user()->can('view-punto_vendita')) {
178 194
             return redirect()->route('punto-vendita.index')
179
-            ->with('error', 'Non hai il permesso di accedere a questo punto di vendita');
195
+                ->with('error', 'Non hai il permesso di accedere a questo punto di vendita');
180 196
         }
181 197
 
182 198
         $puntoVendita = Dispositivo::find(request()->get('punto_vendita_id'));
183
-        if(!$puntoVendita){
199
+        if (! $puntoVendita) {
184 200
             return redirect()->route('punto-vendita.index')
185
-            ->with('error', 'Punto di vendita non trovato');
201
+                ->with('error', 'Punto di vendita non trovato');
186 202
         }
187 203
 
188
-        //se non esiste il binding_token nel DB, lo crea
189
-        if($puntoVendita->binding_token == '' || $puntoVendita->binding_token == null ){
204
+        // se non esiste il binding_token nel DB, lo crea
205
+        if ($puntoVendita->binding_token == '' || $puntoVendita->binding_token == null) {
190 206
             // $puntoVendita->binding_token = Str::random(32);
191 207
             $puntoVendita->binding_token = Str::random(32);
192 208
             $puntoVendita->save();
193 209
         }
194 210
 
195
-        // if(Cookie::has('binding_token')){
196
-        //     if(Cookie::get('binding_token') != $puntoVendita->binding_token  && $puntoVendita->occupato == true){
197
-        //     return redirect()->back()->with('error', 'Dispositivo già associato. Dissociare per potervi accedere.');
198
-        //     }
199
-        // }elseif(Cookie::has('binding_token') && $puntoVendita->occupato == false){
200
-        //     Cookie::queue('binding_token', $puntoVendita->binding_token);
201
-        //     $puntoVendita->occupato = true;
202
-        //     $puntoVendita->save();
203
-        // }
204
-
205
-        switch(true){
211
+     
212
+        $occupato = $puntoVendita->occupato;
213
+        $CookieBindingToken = Cookie::get('binding_token');
214
+        $BindingTokenPuntoVendita = $puntoVendita->binding_token;
215
+        $stessoDispositivo = $CookieBindingToken == $BindingTokenPuntoVendita;
216
+
217
+        switch (true) {
206 218
             // nessun cookie e il dispositivo non è occupato ACCEDI
207
-            case (!Cookie::has('binding_token') && $puntoVendita->occupato == false):
219
+            case ! $CookieBindingToken && $occupato == false:
208 220
                 Cookie::queue('binding_token', $puntoVendita->binding_token);
221
+
209 222
                 $puntoVendita->occupato = true;
210 223
                 $puntoVendita->save();
211
-            break;
212
-
213
-            //nessun cookie e il dispositivo è occupato 01 NON ACCEDI
214
-            case (!Cookie::has('binding_token') && $puntoVendita->occupato == true):
215
-                return redirect()->back()->with('error', 'Dispositivo già occupato. Dissociare per potervi accedere.');
216
-            break;
217
-            //cookie esiste e dispositivo non è occupato 10 ACCEDI
218
-            case (Cookie::has('binding_token') && $puntoVendita->occupato == false):
219
-                if(Cookie::get('binding_token') == $puntoVendita->binding_token){
224
+                break;
225
+
226
+                // nessun cookie e il dispositivo è occupato 01 NON ACCEDI, c'è qualcun'altro
227
+            case ! $CookieBindingToken && $occupato == true:
228
+
229
+                if ($isDataTableDrawRequest) {
230
+                    // Prosegue senza interrompere la risposta DataTable.
231
+                } else {
232
+                    return redirect()->route('punto-vendita.index')->with('error', 'Dispositivo già occupato. Dissociare per potervi accedere.');
233
+                }
234
+                break;
235
+
236
+                // cookie esiste e dispositivo non è occupato 10 ACCEDI
237
+            case $CookieBindingToken && $occupato == false:
238
+
239
+                if ($stessoDispositivo) {
220 240
                     $puntoVendita->occupato = true;
221 241
                     $puntoVendita->save();
222 242
                     break;
223
-                }else{
224
-                    return redirect()->back()->with('error', 'Dispositivo già occupato. Dissociare per potervi accedere.');
243
+
244
+                } else {
245
+
246
+                    Dispositivo::where('id', '!=', $puntoVendita->id)
247
+                        ->where('binding_token', $CookieBindingToken)
248
+                        ->update(['occupato' => false]);
249
+
250
+                    Cookie::queue('binding_token', $puntoVendita->binding_token);
251
+                    $puntoVendita->occupato = true;
252
+                    $puntoVendita->save();
225 253
                 }
226
-            break;
227
-            // cookie esiste e dispositivo è occupato 11 ACCEDI SE SEI TU
228
-            case (Cookie::has('binding_token') && $puntoVendita->occupato == true):
229
-                if(Cookie::get('binding_token') == $puntoVendita->binding_token){
254
+                break;
255
+
256
+                // cookie esiste e dispositivo è occupato 11 ACCEDI SE SEI TU
257
+            case $CookieBindingToken && $occupato == true:
258
+
259
+                if ($stessoDispositivo) {
230 260
                     break;
231
-                }else{
232
-                    return redirect()->back()->with('error', 'Dispositivo già occupato. Dissociare per potervi accedere.');
261
+
262
+                } else {
263
+                    
264
+                    if ($isDataTableDrawRequest) {
265
+                        // Prosegue senza interrompere la risposta DataTable.
266
+                    } else {
267
+                        dd('11, altro dispositivo', json_encode(request()->cookie()));
268
+
269
+                        return redirect()->route('punto-vendita.index')->with('error', 'Dispositivo già occupato. Dissociare per potervi accedere.');
270
+                    }
233 271
                 }
234
-            break;
272
+                break;
235 273
 
236 274
         }
237
-  
238
-   
239 275
 
240 276
         // dd(Cookie::get('binding_token'));
241 277
         $cucine = $puntoVendita->cucine()
@@ -248,43 +284,45 @@ class PuntoVenditaController extends Controller
248 284
             ->orderBy('nome')
249 285
             ->get();
250 286
 
251
-
252
-
253 287
         $ordine = Ordine::firstOrCreate([
254 288
             'stato' => Ordine::CARRELLO,
255 289
             'dispositivo_id' => $puntoVendita->id,
256 290
             'attivita_id' => $puntoVendita->attivita_id,
257 291
         ]);
258
-                Session::put([
259
-                    'dispositivo_id' => $puntoVendita->id,
260
-                    'attivita_id' => $puntoVendita->attivita_id,
261
-                ]);
292
+
293
+        Session::put([
294
+            'dispositivo_id' => $puntoVendita->id,
295
+            'attivita_id' => $puntoVendita->attivita->id,
296
+            'attivita_attuale' => $puntoVendita->attivita->id,
297
+        ]);
298
+        // dd(Session::all());
262 299
 
263 300
         $dataTable->ordine_id = $ordine->id;
264
-        
265
-        if($request->has('vista') && $request->vista == 'catalogo'){
301
+
302
+        if ($request->has('vista') && $request->vista == 'catalogo') {
266 303
             $dataTable->vista = 'catalogo';
267 304
         }
268 305
 
269
-                switch($puntoVendita->tipo){
270
-                    case Dispositivo::CASSA:
271
-                        if($request->has('vista') && $request->vista == 'catalogo'){
272
-                            return $dataTable->render('punto_vendita.cassa.viste.catalogo.index', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable , 'vista' => 'catalogo']);
273
-                        }else{
274
-                        return $dataTable->render('punto_vendita.cassa.index', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
275
-                        }
276
-                        // return $dataTable->render('punto_vendita.cassa.vista2', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
277
-                    case Dispositivo::KIOSK:
278
-                        return $dataTable->render('punto_vendita.kiosk.index', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
279
-                    case Dispositivo::CAMERIERE:
280
-                        return $dataTable->render('punto_vendita.cam.index', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
281
-                };
306
+        switch ($puntoVendita->tipo) {
307
+            case Dispositivo::CASSA:
308
+                if ($request->has('vista') && $request->vista == 'catalogo') {
309
+                    return $dataTable->render('punto_vendita.cassa.viste.catalogo.index', ['punto_vendita' => $puntoVendita, 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable, 'vista' => 'catalogo']);
310
+                } else {
311
+                    return $dataTable->render('punto_vendita.cassa.index', ['punto_vendita' => $puntoVendita, 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
312
+                }
313
+                // return $dataTable->render('punto_vendita.cassa.vista2', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
314
+            case Dispositivo::KIOSK:
315
+                return $dataTable->render('punto_vendita.kiosk.index', ['punto_vendita' => $puntoVendita, 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
316
+            case Dispositivo::CAMERIERE:
317
+                return $dataTable->render('punto_vendita.cam.index', ['punto_vendita' => $puntoVendita, 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
318
+        }
282 319
     }
283 320
 
284
-    public function dissocia_dispositivo(Request $request){
321
+    public function dissocia_dispositivo(Request $request)
322
+    {
285 323
         $puntoVendita = Dispositivo::find($request->punto_vendita_id);
286 324
 
287
-        if(!$puntoVendita){
325
+        if (! $puntoVendita) {
288 326
             return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
289 327
         }
290 328
 
@@ -300,31 +338,31 @@ class PuntoVenditaController extends Controller
300 338
     public function riepilogo(Request $request)
301 339
     {
302 340
         $ordine = Ordine::find($request->ordine_id);
303
-        if(!$ordine){
341
+        if (! $ordine) {
304 342
             return redirect()->route('punto-vendita.kiosk.index')
305
-            ->with('error', 'Ordine non trovato');
343
+                ->with('error', 'Ordine non trovato');
306 344
         }
307
-        
345
+
308 346
         return view('punto_vendita.kiosk.riepilogo', ['ordine' => $ordine]);
309 347
     }
310 348
 
311 349
     public function dettagli(Request $request)
312 350
     {
313 351
         $puntoVendita = Dispositivo::find($request->punto_vendita_id);
314
-        if(!$puntoVendita){
352
+        if (! $puntoVendita) {
315 353
             return redirect()->route('punto-vendita.index')
316
-            ->with('error', 'Punto di vendita non trovato');
354
+                ->with('error', 'Punto di vendita non trovato');
317 355
         }
356
+
318 357
         return view('punto_vendita.dettagli', ['puntoVendita' => $puntoVendita]);
319 358
     }
320
-    
321
-    
359
+
322 360
     public function riepilogo_cassa(Request $request)
323 361
     {
324 362
         $puntoVendita = Dispositivo::find($request->punto_vendita_id);
325
-        if(!$puntoVendita){
363
+        if (! $puntoVendita) {
326 364
             return redirect()->route('punto-vendita.index')
327
-            ->with('error', 'Punto di vendita non trovato');
365
+                ->with('error', 'Punto di vendita non trovato');
328 366
         }
329 367
         // Calcola la data di oggi
330 368
         $oggi = now()->startOfDay();
@@ -380,35 +418,36 @@ class PuntoVenditaController extends Controller
380 418
     {
381 419
         $codice = $request->get('codice');
382 420
         // $pre_ordine = \App\Models\SaltacodaOrdine::where('codice' , $codice)->first();
383
-        $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', 'like', '%PRE_' . strtoupper($codice) . '%')->first();
421
+        $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', 'like', '%PRE_'.strtoupper($codice).'%')->first();
384 422
 
385 423
         // Se non trovato, prova con "PRE_" come prefisso se non già presente
386
-        if (!$pre_ordine && stripos($codice, 'PRE_') !== 0) {
387
-            $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', 'like', '%PRE_' . strtoupper($codice) . '%')->first();
424
+        if (! $pre_ordine && stripos($codice, 'PRE_') !== 0) {
425
+            $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', 'like', '%PRE_'.strtoupper($codice).'%')->first();
388 426
         }
389 427
 
390
-        if(!$pre_ordine){
428
+        if (! $pre_ordine) {
391 429
             return response()->json(['success' => false, 'message' => 'Pre-ordine non trovato']);
392 430
         }
393
-        
394
-        if(!(Session::has('attivita_attuale') && Session::get('attivita_attuale') != null && (int) Session::get('attivita_attuale') == (int) $pre_ordine->attivita_id)){
431
+
432
+        if (! (Session::has('attivita_attuale') && Session::get('attivita_attuale') != null && (int) Session::get('attivita_attuale') == (int) $pre_ordine->attivita_id)) {
395 433
             return response()->json(['success' => false, 'message' => 'Pre-ordine non trovato']);
396 434
         }
435
+
397 436
         return view('punto_vendita.cassa._partials.pre_ordine', ['pre_ordine' => $pre_ordine]);
398 437
 
399 438
     }
400
-    
401 439
 
402
-    public function importa_pre_ordine(Request $request) {
440
+    public function importa_pre_ordine(Request $request)
441
+    {
403 442
 
404 443
         // dd($request->all());
405 444
         $codice = $request->get('codice');
406
-        $pre_ordine = \App\Models\SaltacodaOrdine::where('codice' , $codice)->first();
407
-        if(!$pre_ordine){
445
+        $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', $codice)->first();
446
+        if (! $pre_ordine) {
408 447
             return response()->json(['success' => false, 'message' => 'Pre-ordine non trovato']);
409 448
         }
410
-        
411
-        if(!(Session::has('attivita_attuale') && Session::get('attivita_attuale') != null && (int) Session::get('attivita_attuale') == (int) $pre_ordine->attivita_id)){
449
+
450
+        if (! (Session::has('attivita_attuale') && Session::get('attivita_attuale') != null && (int) Session::get('attivita_attuale') == (int) $pre_ordine->attivita_id)) {
412 451
             return response()->json(['success' => false, 'message' => 'Attività non trovata']);
413 452
         }
414 453
 
@@ -420,19 +459,19 @@ class PuntoVenditaController extends Controller
420 459
 
421 460
         $ordine = Ordine::find($request->ordine_id);
422 461
 
423
-        if(!$ordine){
462
+        if (! $ordine) {
424 463
             return response()->json(['success' => false, 'message' => 'Ordine non trovato']);
425 464
         }
426 465
 
427
-        if($ordine->stato != Ordine::CARRELLO){
466
+        if ($ordine->stato != Ordine::CARRELLO) {
428 467
             return response()->json(['success' => false, 'message' => 'Ordine non è in carrello']);
429 468
         }
430 469
 
431
-        //compila ordine con i dati del pre-ordine
470
+        // compila ordine con i dati del pre-ordine
432 471
         $ordine->info = $pre_ordine->info;
433 472
         $ordine->save();
434
-        
435
-        foreach($pre_ordine->riga_ordine as $riga_ordine){
473
+
474
+        foreach ($pre_ordine->riga_ordine as $riga_ordine) {
436 475
             \App\Models\RigaOrdine::create([
437 476
                 'ordine_id' => $ordine->id,
438 477
                 'piatto_id' => $riga_ordine->piatto_id,
@@ -442,7 +481,7 @@ class PuntoVenditaController extends Controller
442 481
             ]);
443 482
         }
444 483
 
445
-        //elimina pre-ordine
484
+        // elimina pre-ordine
446 485
         $pre_ordine->stato = \App\Models\SaltacodaOrdine::IMPORTATO;
447 486
         $pre_ordine->save();
448 487
 

+ 108
- 0
app/Http/Controllers/VariantePiattoController.php Datei anzeigen

@@ -0,0 +1,108 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use Illuminate\Http\Request;
6
+use App\Models\VariantePiatto;
7
+use App\DataTables\VariantePiattoDataTable;
8
+use App\DataTables\VariantePiattoDataTableEditor;
9
+use Illuminate\Support\Facades\Session;
10
+use Illuminate\Support\Facades\Auth;
11
+
12
+class VariantePiattoController extends Controller
13
+{
14
+    public static $permission_group = "Varianti Piatto";
15
+    public static $permissions = [
16
+        'view-variante-piatto' => 'Vedi',
17
+        'create-variante-piatto' => 'Crea',
18
+        'edit-variante-piatto' => 'Modifica',
19
+        'delete-variante-piatto' => 'Elimina',
20
+    ];
21
+
22
+    public static function middleware(): array
23
+    {
24
+        return [
25
+            new Middleware('permission:view-variante-piatto', only: ['index']),
26
+            new Middleware('permission:create-variante-piatto|edit-variante-piatto|delete-variante-piatto', only: ['store', 'update', 'destroy']),
27
+        ];
28
+    }
29
+
30
+    public function index(VariantePiattoDataTable $dataTable)
31
+    {
32
+        $dataTable->attivita_id = Session::get('attivita_attuale');
33
+
34
+        if (request()->boolean('dashboard')) {
35
+            $dataTable->dashboard = true;
36
+        }
37
+
38
+        if (request()->has('cucina_id')) {
39
+            $dataTable->cucina_id = (int) request()->get('cucina_id');
40
+        }
41
+
42
+        return $dataTable->render('variante_piatto.index');
43
+    }
44
+
45
+    public function store(VariantePiattoDataTableEditor $editor)
46
+    {
47
+        $request = request();
48
+        $input = $request->all();
49
+        if($request->has('action')){
50
+          switch($input['action']){
51
+            case 'create':
52
+              if(!Auth::user()->can('create-variante-piatto')) return;
53
+              break;
54
+            case 'edit':
55
+              if(!Auth::user()->can('edit-variante-piatto')) return;
56
+              break;
57
+            case 'remove':
58
+              if(!Auth::user()->can('delete-variante-piatto')) return;
59
+              break;
60
+          }
61
+        }
62
+        return $editor->process($request);
63
+    }
64
+
65
+    public function datatable(VariantePiattoDataTable $dataTable , Request $request){
66
+        $dataTable->attivita_id = Session::get('attivita_attuale');
67
+  
68
+        if(request()->has('cucina_id')){
69
+          $dataTable->cucina_id = request()->get('cucina_id');
70
+        }
71
+        if(request()->has('dashboard')){
72
+          $dataTable->dashboard = true;
73
+        }
74
+  
75
+          return $dataTable->render('variante_piatto.datatable');
76
+      }
77
+
78
+    public function list(Request $request){
79
+        $attivita = \App\Models\Attivita::find(Session::get('attivita_attuale'));
80
+        if(!$attivita){
81
+          return response()->json([
82
+            'success' => false,
83
+            'message' => 'Attività non trovata',
84
+          ]);
85
+        }
86
+        $rigaOrdine = \App\Models\RigaOrdine::find($request->riga_ordine_id);
87
+        if(!$rigaOrdine){
88
+          return response()->json([
89
+            'success' => false,
90
+            'message' => 'Riga ordine non trovata',
91
+          ]);
92
+        }
93
+    
94
+      $variantiCucina = VariantePiatto::query()
95
+      ->where('attivita_id', $attivita->id)
96
+      ->where('cucina_id',$rigaOrdine->piatto->cucina->id);
97
+
98
+      $variantiPiatto = VariantePiatto::query()
99
+      ->where('attivita_id', $attivita->id)
100
+      ->where('piatto_id',$rigaOrdine->piatto->id);
101
+
102
+
103
+      return response()->json([
104
+        'variantiCucina' => $variantiCucina->get(),
105
+        'variantiPiatto' => $variantiPiatto->get(),
106
+      ]);
107
+    }
108
+}

+ 5
- 1
app/Models/AbstractModels/AbstractRigaOrdine.php Datei anzeigen

@@ -72,5 +72,9 @@ abstract class AbstractRigaOrdine extends \Illuminate\Foundation\Auth\User
72 72
     {
73 73
         return $this->belongsTo('\App\Models\Ordine', 'ordine_id', 'id');
74 74
     }
75
-    
75
+
76
+    public function has_variante()
77
+    {
78
+        return $this->hasMany('\App\Models\RigaOrdineHasVariante', 'riga_ordine_id', 'id');
79
+    }
76 80
 }

+ 69
- 0
app/Models/AbstractModels/AbstractRigaOrdineHasVariante.php Datei anzeigen

@@ -0,0 +1,69 @@
1
+<?php
2
+/**
3
+ * Model object generated by: Skipper (http://www.skipper18.com)
4
+ * Do not modify this file manually.
5
+ */
6
+
7
+namespace App\Models\AbstractModels;
8
+
9
+abstract class AbstractRigaOrdineHasVariante extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'riga_ordine_has_variante';
17
+    
18
+    /**  
19
+     * Primary key type.
20
+     * 
21
+     * @var string
22
+     */
23
+    protected $keyType = 'bigInteger';
24
+    
25
+    /**  
26
+     * The model's default values for attributes.
27
+     * 
28
+     * @var array
29
+     */
30
+    // protected $attributes = ['is_gruppo' => 0];
31
+    
32
+    /**  
33
+     * The attributes that should be cast to native types.
34
+     * 
35
+     * @var array
36
+     */
37
+    protected $casts = [
38
+        'id' => 'integer',
39
+        'riga_ordine_id' => 'integer',
40
+        'variante_id' => 'integer',
41
+        'nota' => 'string',
42
+        'created_at' => 'datetime',
43
+        'updated_at' => 'datetime'
44
+    ];
45
+
46
+    /**  
47
+     * The attributes that are mass assignable.
48
+     * 
49
+     * @var array
50
+     */
51
+    protected $fillable = [
52
+        'id',
53
+        'riga_ordine_id',
54
+        'variante_id',
55
+        'nota',
56
+        'created_at',
57
+        'updated_at'
58
+    ];
59
+    
60
+    public function riga_ordine()
61
+    {
62
+        return $this->belongsTo('\App\Models\RigaOrdine', 'riga_ordine_id', 'id');
63
+    }
64
+
65
+    public function variante_piatto()
66
+    {
67
+        return $this->belongsTo('\App\Models\VariantePiatto', 'variante_id', 'id');
68
+    }
69
+}

+ 11
- 1
app/Models/AbstractModels/AbstractVariantePiatto.php Datei anzeigen

@@ -37,6 +37,7 @@ abstract class AbstractVariantePiatto extends \Illuminate\Foundation\Auth\User
37 37
     protected $casts = [
38 38
         'id' => 'integer',
39 39
         'attivita_id' => 'integer',
40
+        'cucina_id' => 'integer',
40 41
         'piatto_id' => 'integer',
41 42
         'label' => 'string',
42 43
         'prezzo' => 'decimal:2',
@@ -53,6 +54,7 @@ abstract class AbstractVariantePiatto extends \Illuminate\Foundation\Auth\User
53 54
     protected $fillable = [
54 55
         'id',
55 56
         'attivita_id',
57
+        'cucina_id',
56 58
         'piatto_id',
57 59
         'label',
58 60
         'prezzo',
@@ -70,5 +72,13 @@ abstract class AbstractVariantePiatto extends \Illuminate\Foundation\Auth\User
70 72
     {
71 73
         return $this->belongsTo('\App\Models\Piatto', 'piatto_id', 'id');
72 74
     }
73
-    
75
+
76
+    public function cucina()
77
+    {
78
+        return $this->belongsTo('\App\Models\Cucina', 'cucina_id', 'id');
79
+    }
80
+    public function has_riga_ordine()
81
+    {
82
+        return $this->hasMany('\App\Models\RigaOrdineHasVariante', 'variante_id', 'id');
83
+    }
74 84
 }

+ 10
- 0
app/Models/RigaOrdineHasVariante.php Datei anzeigen

@@ -0,0 +1,10 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Relations\Pivot;
6
+
7
+class RigaOrdineHasVariante extends \App\Models\AbstractModels\AbstractRigaOrdineHasVariante
8
+{
9
+    //
10
+}

+ 197
- 9
app/Services/Carrello/CarrelloService.php Datei anzeigen

@@ -5,6 +5,8 @@ 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\VariantePiatto;
9
+use App\Models\RigaOrdineHasVariante;
8 10
 use Illuminate\Database\Eloquent\ModelNotFoundException;
9 11
 
10 12
 class CarrelloService
@@ -20,7 +22,7 @@ class CarrelloService
20 22
         return $ordine;
21 23
     }
22 24
 
23
-    public function aumentaQuantita(int $dispositivo_id ,?int $attivita_id, ?int $ordine_id, int $piatto_id): array
25
+    public function aumentaQuantita(int $dispositivo_id ,?int $attivita_id, ?int $ordine_id, int $piatto_id, int $riga_ordine_id = null): array
24 26
     {
25 27
     // Tolleranza su ordine_id stale: se non e` valido, usa/crea il carrello corrente per dispositivo+attivita.
26 28
         $carrelloBaseQuery = Ordine::query()
@@ -50,11 +52,23 @@ class CarrelloService
50 52
             ]);
51 53
         }
52 54
 
53
-        $riga = RigaOrdine::where('ordine_id', $carrello->id)->where('piatto_id', $piatto_id)->first();
55
+        if($riga_ordine_id){
56
+            $riga = RigaOrdine::findOrFail($riga_ordine_id);
57
+        }else{
58
+            $riga = RigaOrdine::where('ordine_id', $carrello->id)->where('piatto_id', $piatto_id)->first();
59
+        }
60
+
54 61
         $piatto = Piatto::findOrFail($piatto_id);
55 62
         if($riga){
56 63
             $riga->quantita += 1;
57
-            $riga->prezzo = $piatto->prezzo*$riga->quantita;
64
+            $parziale = $piatto->prezzo*$riga->quantita;
65
+            //Se ha delle varianti a pagamento, aggiungo il prezzo delle varianti * quantita
66
+            if($riga->has_variante->isNotEmpty()){
67
+                foreach($riga->has_variante as $variante){
68
+                    $parziale += $variante->variante_piatto->prezzo * $riga->quantita;
69
+                }
70
+            }
71
+            $riga->prezzo = $parziale ;//$piatto->prezzo*$riga->quantita;
58 72
             $riga->save();
59 73
         }else{
60 74
             $riga = RigaOrdine::create([
@@ -74,11 +88,22 @@ class CarrelloService
74 88
     public function diminuisciQuantita(int $ordine_id, int $piatto_id, int $riga_ordine_id): array
75 89
     {
76 90
         $carrello = Ordine::findOrFail($ordine_id);
77
-        $riga = RigaOrdine::where('ordine_id', $carrello->id)->where('piatto_id', $piatto_id)->first();
91
+        // $riga = RigaOrdine::where('ordine_id', $carrello->id)->where('piatto_id', $piatto_id)->first();
92
+        $riga = RigaOrdine::findOrFail($riga_ordine_id);
78 93
         if($riga && $riga->id == $riga_ordine_id){
79 94
             $piatto = Piatto::findOrFail($piatto_id);
80 95
             $riga->quantita -= 1;
81
-            $riga->prezzo = $piatto->prezzo*$riga->quantita;
96
+            // dd($riga->quantita);
97
+
98
+            $parziale = $piatto->prezzo*$riga->quantita;
99
+            // dd($parziale);
100
+            //Se ha delle varianti a pagamento, aggiungo il prezzo delle varianti * quantita
101
+            if($riga->has_variante->isNotEmpty()){
102
+                foreach($riga->has_variante as $variante){
103
+                    $parziale += $variante->variante_piatto->prezzo * $riga->quantita;
104
+                }
105
+            }
106
+            $riga->prezzo = $parziale ;//$piatto->prezzo*$riga->quantita;
82 107
             $riga->save();   
83 108
         }
84 109
         return [
@@ -133,17 +158,180 @@ class CarrelloService
133 158
         // }
134 159
     }
135 160
 
136
-    public function aggiornaNota(int $rigaOrdineId, string $note): RigaOrdine
161
+    public function aggiornaNota(int $rigaOrdineId, string $note = null): RigaOrdine
137 162
     {
138 163
         $riga = RigaOrdine::findOrFail($rigaOrdineId);
139 164
         if($riga == null){
140 165
             throw new ModelNotFoundException('Riga ordine non trovata.');
141 166
         };
142
-        if($note == null){
143
-            throw new ValidationException('Nota non valida.');
144
-        }
167
+
145 168
         $riga->note = $note;
146 169
         $riga->save();
147 170
         return $riga;
148 171
     }
172
+
173
+    public function aggiungiVarianteSingoloPiatto(int $piattoId, int $rigaOrdineId, int $varianteId = null, string $nota = null): array
174
+    {
175
+        $riga = RigaOrdine::findOrFail($rigaOrdineId);
176
+        if($riga == null){
177
+            return [
178
+                'success' => false,
179
+                'message' => 'Riga ordine non trovata.',
180
+                'data' => null,
181
+            ];
182
+        }
183
+        $variante = VariantePiatto::findOrFail($varianteId);
184
+        if($variante == null){
185
+            return [
186
+                'success' => false,
187
+                'message' => 'Variante non trovata.',
188
+                'data' => null,
189
+            ];
190
+        }
191
+        $piatto = Piatto::findOrFail($piattoId);
192
+        if($piatto == null){
193
+            return [
194
+                'success' => false,
195
+                'message' => 'Piatto non trovato.',
196
+                'data' => null,
197
+            ];
198
+        }
199
+
200
+        if($riga->quantita == 1){
201
+            $pivotVariante = RigaOrdineHasVariante::create([
202
+                'riga_ordine_id' => $riga->id,
203
+                'variante_id' => $varianteId,
204
+                // 'nota' => $nota,
205
+            ]);
206
+
207
+            $riga->prezzo = ($piatto->prezzo * $riga->quantita) + ($variante->prezzo * $riga->quantita);
208
+            $riga->save();
209
+            return [
210
+                'success' => true,
211
+                'message' => 'Variante aggiunta al piatto',
212
+                'data' => $pivotVariante,
213
+            ];
214
+        }
215
+
216
+        $NuovaRigaPerVariante = RigaOrdine::create([
217
+            'ordine_id' => $riga->ordine_id,
218
+            'piatto_id' => $piattoId,
219
+            'quantita' => 1,
220
+            'prezzo' => $piatto->prezzo,
221
+            'note' => $nota,
222
+        ]);
223
+
224
+        $pivotVariante = RigaOrdineHasVariante::create([
225
+            'riga_ordine_id' => $NuovaRigaPerVariante->id,
226
+            'variante_id' => $varianteId,
227
+            // 'nota' => $nota,
228
+        ]);
229
+
230
+        $riga->quantita -= 1;
231
+        $riga->save();
232
+
233
+        $NuovaRigaPerVariante->prezzo = ($piatto->prezzo * $NuovaRigaPerVariante->quantita) + ($variante->prezzo * $NuovaRigaPerVariante->quantita);
234
+        $NuovaRigaPerVariante->save();
235
+        // dd($NuovaRigaPerVariante ,$riga, $pivotVariante);
236
+        return [
237
+            'success' => true,
238
+            'message' => 'Variante aggiornata',
239
+            'data' => $NuovaRigaPerVariante,
240
+        ];
241
+    }
242
+
243
+    // public function aggiungiVarianteTuttiPiatto(int $piattoId, int $rigaOrdineId, int $varianteId, string $nota): array
244
+    // {
245
+    //     $riga = RigaOrdine::find($rigaOrdineId);
246
+    //     if (!$riga) {
247
+    //         return [
248
+    //             'success' => false,
249
+    //             'message' => 'Riga ordine non trovata.',
250
+    //             'data' => null,
251
+    //         ];
252
+    //     }
253
+
254
+    //     $piatto = Piatto::find($piattoId);
255
+    //     if (!$piatto) {
256
+    //         return [
257
+    //             'success' => false,
258
+    //             'message' => 'Piatto non trovato.',
259
+    //             'data' => null,
260
+    //         ];
261
+    //     }
262
+
263
+    //     $quantitaOriginale = $riga->quantita;
264
+
265
+    //     if ($quantitaOriginale <= 1) {
266
+    //         // Non c'è niente da splittare, quindi niente copie da fare
267
+    //         return [
268
+    //             'success' => false,
269
+    //             'message' => 'Non ci sono abbastanza piatti per dividere in varianti.',
270
+    //             'data' => null,
271
+    //         ];
272
+    //     }
273
+
274
+    //     for ($i = 1; $i < $quantitaOriginale; $i++) {
275
+    //         RigaOrdine::create([
276
+    //             'ordine_id' => $riga->ordine_id,
277
+    //             'piatto_id' => $piattoId,
278
+    //             'quantita' => 1,
279
+    //             'prezzo' => $piatto->prezzo,
280
+    //         ]);
281
+    //     }
282
+    //     $riga->quantita = 1;
283
+    //     $riga->save();
284
+
285
+    //     return [
286
+    //         'success' => true,
287
+    //         'message' => 'Riga ordine per variante aggiunta per tutti i piatti',
288
+    //         'data' => null,
289
+    //     ];
290
+    // }
291
+
292
+    public function eliminaVariante(int $rigaOrdineId, int $varianteId): array
293
+    {
294
+        $riga = RigaOrdine::findOrFail($rigaOrdineId);
295
+        if($riga == null){
296
+            return [
297
+                'success' => false,
298
+                'message' => 'Riga ordine non trovata.',
299
+                'data' => null,
300
+            ];
301
+        }
302
+        $variante = VariantePiatto::findOrFail($varianteId);
303
+        if($variante == null){
304
+            return [
305
+                'success' => false,
306
+                'message' => 'Variante non trovata.',
307
+                'data' => null,
308
+            ];
309
+        }
310
+        $pivotVariante = RigaOrdineHasVariante::where('riga_ordine_id', $riga->id)->where('variante_id', $varianteId)->first();
311
+        if($pivotVariante == null){
312
+            return [
313
+                'success' => false,
314
+                'message' => 'Variante non trovata.',
315
+                'data' => null,
316
+            ];
317
+        }
318
+        $pivotVariante->delete();
319
+        
320
+        $parziale = $riga->piatto->prezzo*$riga->quantita;
321
+            // dd($parziale);
322
+            //Se ha delle varianti a pagamento, aggiungo il prezzo delle varianti * quantita
323
+            if($riga->has_variante->isNotEmpty()){
324
+                foreach($riga->has_variante as $variante){
325
+                    $parziale += $variante->variante_piatto->prezzo * $riga->quantita;
326
+                }
327
+            }
328
+            $riga->prezzo = $parziale ;//$piatto->prezzo*$riga->quantita;
329
+            $riga->save();  
330
+            
331
+        return [
332
+            'success' => true,
333
+            'message' => 'Variante eliminata',
334
+            'data' => null,
335
+        ];
336
+    }
149 337
 }

+ 6
- 1
app/Services/Stampa/CreaComandaCucina.php Datei anzeigen

@@ -20,7 +20,7 @@ class CreaComandaCucina
20 20
      */
21 21
     public function perOrdine(Ordine $ordine, int $cucina_id): array
22 22
     {
23
-        $ordine->loadMissing(['righe_ordine.piatto', 'dispositivo']);
23
+        $ordine->loadMissing(['righe_ordine.piatto', 'dispositivo', 'righe_ordine.has_variante.variante_piatto']);
24 24
         $cucina = Cucina::find($cucina_id);
25 25
         if ($cucina === null) {
26 26
             Log::error('--- CreaComandaCucina --- Cucina non trovata id: '.$cucina_id);
@@ -186,6 +186,11 @@ class CreaComandaCucina
186 186
                 }
187 187
                 $printer->setTextSize(1, 1);
188 188
             }
189
+            if($riga->has_variante->isNotEmpty()){
190
+                foreach($riga->has_variante as $variante){
191
+                    $printer->text(">> ".$variante->variante_piatto->label."\n");
192
+                }
193
+            }
189 194
 
190 195
             $printer->text("\n");
191 196
         }

+ 22
- 1
app/Services/Stampa/CreaScontrino.php Datei anzeigen

@@ -19,7 +19,7 @@ class CreaScontrino
19 19
      */
20 20
     public function perOrdine(Ordine $ordine): array
21 21
     {
22
-        $ordine->loadMissing(['righe_ordine.piatto', 'attivita', 'metodo_pagamento', 'dispositivo']);
22
+        $ordine->loadMissing(['righe_ordine.piatto', 'attivita', 'metodo_pagamento', 'dispositivo', 'righe_ordine.has_variante.variante_piatto']);
23 23
 
24 24
         $connector = new DummyPrintConnector;
25 25
         $printer = new Printer($connector);
@@ -134,6 +134,27 @@ class CreaScontrino
134 134
                     $printer->text(str_repeat(' ', self::COL_QTA_WIDTH).$noteLine."\n");
135 135
                 }
136 136
             }
137
+            // Stampa le varianti nello stesso formato delle voci dei piatti (con wrapping)
138
+            if($riga->has_variante->isNotEmpty()){
139
+                foreach($riga->has_variante as $variante){
140
+                    $label = ">> " . $variante->variante_piatto->label;
141
+                    $prezzo = $this->moneyShort($variante->variante_piatto->prezzo ?? 0);
142
+                    $varianteLines = $this->wrapText($this->sanitizeLine($label), $itemWidth);
143
+                    $firstVarianteLine = $varianteLines[0] ?? '';
144
+                    $printer->text(
145
+                        str_repeat(' ', self::COL_QTA_WIDTH) .
146
+                        str_pad($firstVarianteLine, $itemWidth) .
147
+                        str_pad($prezzo, self::COL_TOTAL_WIDTH, ' ', STR_PAD_LEFT) . "\n"
148
+                    );
149
+                    for ($j = 1; $j < count($varianteLines); $j++) {
150
+                        $printer->text(
151
+                            str_repeat(' ', self::COL_QTA_WIDTH) .
152
+                            str_pad($varianteLines[$j], $itemWidth) . "\n"
153
+                        );
154
+                    }
155
+                }
156
+            }
157
+    
137 158
         }
138 159
     }
139 160
 

+ 6
- 0
database/migrations/2026_06_20_143147_create_variantes_table.php Datei anzeigen

@@ -18,8 +18,14 @@ return new class extends Migration
18 18
             $table->string('label')->nullable();
19 19
             $table->decimal('prezzo', 10, 2)->nullable();
20 20
             $table->boolean('is_attivo')->default(true);
21
+            $table->bigInteger('cucina_id')->unsigned()->nullable();
21 22
             $table->timestamps();
22 23
         });
24
+        Schema::table('variante_piatto', function (Blueprint $table) {
25
+            $table->foreign('attivita_id')->references('id')->on('attivita');
26
+            $table->foreign('piatto_id')->references('id')->on('piatto');
27
+            $table->foreign('cucina_id')->references('id')->on('cucina');
28
+        });
23 29
     }
24 30
 
25 31
     /**

+ 34
- 0
database/migrations/2026_06_21_223039_create_riga_ordine_has_variante_table.php Datei anzeigen

@@ -0,0 +1,34 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('riga_ordine_has_variante', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->bigInteger('riga_ordine_id')->unsigned()->nullable();
17
+            $table->foreign('riga_ordine_id')->references('id')->on('riga_ordine')->onDelete('cascade');
18
+            $table->bigInteger('variante_id')->unsigned()->nullable();
19
+            $table->foreign('variante_id')->references('id')->on('variante_piatto')->onDelete('cascade');
20
+            $table->string('nota')->nullable();
21
+            $table->timestamps();
22
+
23
+            $table->unique(['riga_ordine_id', 'variante_id']);
24
+        });
25
+    }
26
+
27
+    /**
28
+     * Reverse the migrations.
29
+     */
30
+    public function down(): void
31
+    {
32
+        Schema::dropIfExists('riga_ordine_has_variante');
33
+    }
34
+};

+ 268
- 0
resources/views/cucina/dashboard.blade.php Datei anzeigen

@@ -0,0 +1,268 @@
1
+<?php
2
+use App\Models\Role;
3
+use Illuminate\Support\Facades\Auth;
4
+?>
5
+@php
6
+$configData = Helper::appClasses();
7
+@endphp
8
+
9
+@extends('layouts/layoutMaster')
10
+
11
+@section('title', 'Dashboard Cucina')
12
+
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
22
+
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
37
+
38
+@section('pageTitle')
39
+<div class="d-flex flex-column">
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-chef-hat d-none d-md-inline-flex d-lg-inline-flex"></i> Dashboard Cucine</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Configurazioni</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item text-primary">
50
+                <a href="{{ route('cucina.index') }}">Cucine</a>
51
+              </li>
52
+
53
+            </ol>
54
+          </nav>
55
+</div>
56
+@endsection
57
+
58
+@section('content')
59
+<style>
60
+  div.upload button:first-child{
61
+    display: none !important;
62
+  }
63
+
64
+.bx-chef-hat{
65
+  --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");
66
+}
67
+</style>
68
+
69
+@include('_partials.status')
70
+
71
+<div class="row justify-content-center">
72
+    <!-- cucine -->
73
+  <div class="col-xxl mb-4 mt-2">
74
+    <div class="card">
75
+      <div class="card-header">
76
+        <h5 class="card-title"><i class="bx bx-chef-hat me-1"></i> Cucine</h5>
77
+      </div>
78
+      <div class="card-body">
79
+        {{ $dataTable_cucina->table(['class' => 'table table-bordered']) }}
80
+      </div>
81
+    </div>
82
+  </div>
83
+
84
+  <!-- piatti -->
85
+  <div class="col-xxl mb-4 mt-2">
86
+    <div class="card">
87
+      <div class="card-header">
88
+        <h5 class="card-title"><i class="bx bx-dish me-1"></i> Piatti<span class="cucina_name text-primary"></span></h5>
89
+      </div>
90
+      <div class="card-body" id="dataTable_piatto_div">
91
+        <span class="alert alert-info">Scegli una cucina per visualizzare i piatti</span>
92
+
93
+      </div>
94
+    </div>
95
+  </div>
96
+
97
+  <!-- varianti -->
98
+  <div class="col-xxl mb-4 mt-2">
99
+    <div class="card">
100
+      <div class="card-header">
101
+        <h5 class="card-title"><i class="bx bx-category-alt me-1"></i> Varianti <span class="cucina_name text-primary"></span></h5>
102
+      </div>
103
+      <div class="card-body" id="dataTable_variante_div">
104
+        <span class="alert alert-info">Scegli una cucina per visualizzare le varianti</span>
105
+
106
+      </div>
107
+    </div>
108
+  </div>
109
+
110
+
111
+</div>
112
+
113
+@endsection
114
+
115
+@section('page-script')
116
+
117
+{{$dataTable_cucina->scripts(attributes: ['type' => 'module'])}}
118
+
119
+
120
+
121
+
122
+<script type="module">
123
+  $(document).ready(function(){
124
+    // Editor edit
125
+    $("#dataTable_cucina").on('click', 'a.editor_edit', function (e) {
126
+      e.preventDefault();
127
+      window.LaravelDataTables["dataTable_cucina-editor"].edit( $(this).closest('tr'), {
128
+        title: 'Modifica',
129
+        buttons: 'Aggiorna',
130
+      });
131
+    });
132
+
133
+    // Editor delete
134
+    $("#dataTable_cucina").on('click', 'a.editor_delete', function (e) {
135
+      e.preventDefault();
136
+      window.LaravelDataTables["dataTable_cucina-editor"].remove($(this).closest('tr'), {
137
+        title: 'Cancella record',
138
+        message: 'Sei sicuro di voler eliminare il record selezionato?',
139
+        buttons: 'Cancella record'
140
+      });
141
+    } );
142
+
143
+    $("#dataTable_cucina").on('dblclick', 'tbody td', function (e) {
144
+      window.LaravelDataTables["dataTable_cucina-editor"].edit( $(this).closest('tr'), {
145
+        title: 'Modifica',
146
+        buttons: 'Aggiorna',
147
+      });
148
+    });
149
+
150
+  });
151
+
152
+</script>
153
+
154
+<script type="module">
155
+  $(document).ready(function(){
156
+    // Editor edit
157
+    $("#dataTable_piatto").on('click', 'a.editor_edit', function (e) {
158
+      e.preventDefault();
159
+      window.LaravelDataTables["dataTable_piatto-editor"].edit( $(this).closest('tr'), {
160
+        title: 'Modifica',
161
+        buttons: 'Aggiorna',
162
+      });
163
+    });
164
+
165
+    // Editor delete
166
+    $("#dataTable_piatto").on('click', 'a.editor_delete', function (e) {
167
+      e.preventDefault();
168
+      window.LaravelDataTables["dataTable_piatto-editor"].remove($(this).closest('tr'), {
169
+        title: 'Cancella record',
170
+        message: 'Sei sicuro di voler eliminare il record selezionato?',
171
+        buttons: 'Cancella record'
172
+      });
173
+    } );
174
+
175
+    $("#dataTable_piatto").on('dblclick', 'tbody td', function (e) {
176
+      window.LaravelDataTables["dataTable_piatto-editor"].edit( $(this).closest('tr'), {
177
+        title: 'Modifica',
178
+        buttons: 'Aggiorna',
179
+      });
180
+    });
181
+
182
+  });
183
+
184
+</script>
185
+
186
+
187
+<script type="module">
188
+  $(document).ready(function(){
189
+    // Editor edit
190
+    $("#dataTable_variante").on('click', 'a.editor_edit', function (e) {
191
+      e.preventDefault();
192
+      window.LaravelDataTables["dataTable_variante-editor"].edit( $(this).closest('tr'), {
193
+        title: 'Modifica',
194
+        buttons: 'Aggiorna',
195
+      });
196
+    });
197
+
198
+    // Editor delete
199
+    $("#dataTable_variante").on('click', 'a.editor_delete', function (e) {
200
+      e.preventDefault();
201
+      window.LaravelDataTables["dataTable_variante-editor"].remove($(this).closest('tr'), {
202
+        title: 'Cancella record',
203
+        message: 'Sei sicuro di voler eliminare il record selezionato?',
204
+        buttons: 'Cancella record'
205
+      });
206
+    } );
207
+
208
+    $("#dataTable_variante").on('dblclick', 'tbody td', function (e) {
209
+      window.LaravelDataTables["dataTable_variante-editor"].edit( $(this).closest('tr'), {
210
+        title: 'Modifica',
211
+        buttons: 'Aggiorna',
212
+      });
213
+    });
214
+
215
+  });
216
+
217
+</script>
218
+
219
+<script>
220
+  function initComplete_cucina(){
221
+    $('div.dt-buttons button').removeClass('btn-secondary');
222
+    $('div.dt-search').addClass('mt-0 mb-4');
223
+    return;
224
+  }
225
+
226
+  function initComplete_piatto(){
227
+    $('div.dt-buttons button').removeClass('btn-secondary');
228
+    $('div.dt-search').addClass('mt-0 mb-4');
229
+    return;
230
+  }
231
+
232
+  function initComplete_variante(){
233
+    $('div.dt-buttons button').removeClass('btn-secondary');
234
+    $('div.dt-search').addClass('mt-0 mb-4');
235
+    return;
236
+  }
237
+
238
+
239
+  function showDataTablePiatto(cucina_id, cucina_name){
240
+    $('#dataTable_piatto_div').removeClass('card-body');
241
+    $('#dataTable_variante_div').removeClass('card-body');
242
+    $('.cucina_name').text(' di ' + cucina_name);
243
+    $('#dataTable_piatto_div').load("{{ route('piatto.datatable') }}?cucina_id=" + cucina_id + "&dashboard=true");
244
+    $('#dataTable_variante_div').load("{{ route('variante-piatto.datatable') }}?cucina_id=" + cucina_id + "&dashboard=true");
245
+  }
246
+
247
+  function toggleIsAttivo(punto_operatore_id){
248
+    $.ajax({
249
+      url: "{{ route('punto-operatore.toggle-is-attivo') }}",
250
+      type: 'GET',
251
+      data: { punto_operatore_id: punto_operatore_id },
252
+      success: function(response){
253
+        new Notyf({
254
+          duration: 2000,
255
+          position: { x: 'right', y: 'top' }
256
+        }).success(response.message);
257
+      },
258
+      error: function(xhr, status, error){
259
+        new Notyf({
260
+          duration: 2000,
261
+          position: { x: 'right', y: 'top' }
262
+        }).error(xhr.responseText);
263
+      }
264
+    });
265
+  }
266
+
267
+</script>
268
+@endsection

+ 9
- 1
resources/views/cucina/menu.blade.php Datei anzeigen

@@ -1,27 +1,35 @@
1 1
 <?php
2 2
 use Illuminate\Support\Facades\Auth;
3 3
 ?>
4
-
5 4
 <div class="dropdown">
6 5
     <button type="button" class="btn p-0 dropdown-toggle hide-arrow" data-bs-toggle="dropdown" aria-expanded="false">
7 6
         <i class="bx bx-dots-vertical-rounded fs-large"></i>
8 7
     </button>
9 8
     <div class="dropdown-menu">
10 9
         @if(Auth::user()->can('view-piatto'))
10
+        @if(!$dashboard)
11 11
         <a href="{{ route('piatto.index', ['cucina_id' => $entity->id]) }}" class="dropdown-item">
12 12
             <i class="bx bx-dish me-1"></i> Vedi piatti
13 13
         </a>
14 14
         @endif
15
+        @if($dashboard)
16
+        <a href="#" class="dropdown-item" onclick="showDataTablePiatto({{ $entity->id }},$(this).data('cucina_name'))" event.preventDefault() data-cucina_name="{{ $entity->nome }}">
17
+            <i class="bx bx-dish me-1"></i> Vedi piatti
18
+        </a>
19
+        @endif
20
+        @endif
15 21
         @if(Auth::user()->can('edit-cucina'))
16 22
         <a href="#" class="dropdown-item editor_edit">
17 23
             <i class="bx bx-edit-alt me-1"></i> Modifica
18 24
         </a>
19 25
         @endif
20 26
         @if(Auth::user()->can('view-punto_operatore'))
27
+        @if(!$dashboard)
21 28
         <a href="#" class="dropdown-item toggle_is_attivo" data-punto_operatore_id="{{ $entity->id }}" onclick="toggleIsAttivo({{ $entity->id }})">
22 29
             <i class="bx bx-user me-1"></i> {{ $entity->is_attivo ? 'Disattiva' : 'Attiva' }}
23 30
         </a>
24 31
         @endif
32
+        @endif
25 33
         @if(Auth::user()->can('delete-cucina'))
26 34
         <a href="#" class="dropdown-item editor_delete">
27 35
             <i class="bx bx-trash me-1"></i> Elimina

+ 5
- 8
resources/views/piatto/datatable.blade.php Datei anzeigen

@@ -1,15 +1,12 @@
1 1
 
2
-
3
-
4
-<div class="row justify-content-center">
2
+<!-- <div class="row justify-content-center">
5 3
   <div class="col-xxl mb-4 mt-2">
6
-    <div class="card">
7
-      <div class="card-body">
4
+    <div class="card"> -->
5
+      <div class="card-body pt-0">
8 6
         {{ $dataTable_piatto->table(['class' => 'table table-bordered']) }}
9 7
       </div>
10
-    </div>
8
+    <!-- </div>
11 9
   </div>
12
-</div>
13
-
10
+</div> -->
14 11
 
15 12
  @include('piatto.datatable_script') 

+ 71
- 12
resources/views/punto_vendita/cassa/_partials/carrello/cmd_carrello.blade.php Datei anzeigen

@@ -58,14 +58,32 @@ $piatto = $riga_ordine->piatto??null;
58 58
         {{$riga_ordine->piatto->nome}}
59 59
         <br>
60 60
 
61
-        <small>
61
+        <small class="">
62 62
             @if($riga_ordine->note)
63
-                <i class="bx bx-chat me-2 text-warning" aria-label="Nota"></i> {{ $riga_ordine->note }}
63
+                <i class="bx bx-note me-2 text-warning" aria-label="Nota"></i> {{ $riga_ordine->note }}
64 64
             @else
65
-            <button class=" badge p-1 btn bg-warning text-white align-items-center justify-content-center p-0" onclick="aggiungiNota({{ $piatto_id }}, {{ $riga_ordine_id }}, '')" data-action="aggiungi_nota" data-piatto-id="{{ $piatto_id }}" data-riga-ordine-id="{{ $riga_ordine_id }}">
66
-                <i class="bx bx-plus me-1 " aria-label="Nota"></i> nota
65
+            <button title="Aggiungi nota" class="btn-expand-hover btn btn-primary mt-1" style="padding:revert;" onclick="aggiungiNota({{ $piatto_id }}, {{ $riga_ordine_id }}, '')" data-action="aggiungi_nota" data-piatto-id="{{ $piatto_id }}" data-riga-ordine-id="{{ $riga_ordine_id }}">
66
+                <i class="bx bx-note me-1" aria-label="Nota"></i>
67
+                <span class="btn-expand-label">nota</span>
67 68
             </button>
68 69
             @endif
70
+
71
+            @if($riga_ordine->quantita > 1)
72
+            <button title="Aggiungi variante" class="btn-expand-hover btn btn-primary mt-1" style="padding:revert;" onclick="aggiungiVariante({{ $piatto_id }}, {{ $riga_ordine_id }})" data-action="aggiungi_variante" data-piatto-id="{{ $piatto_id }}" data-riga-ordine-id="{{ $riga_ordine_id }}">
73
+                <i class="bx bx-category-alt me-1" aria-label="Variante"></i>
74
+                <span class="btn-expand-label">variante</span>
75
+            </button>
76
+            @endif
77
+            <!-- <button 
78
+            title="Elimina dal carrello"
79
+                class="btn-expand-hover btn btn-danger mt-1"
80
+                style="padding:revert;"
81
+                onclick="eliminaRiga({{ $piatto->id }}, {{ $riga_ordine_id }})" 
82
+                data-action="elimina" data-piatto-id="{{ $piatto->id }}" data-riga-ordine-id="{{ $riga_ordine_id }}">
83
+                <i class="bx bx-trash"></i>
84
+                <span class="btn-expand-label">elimina</span>
85
+            </button> -->
86
+            
69 87
         <!-- </small>
70 88
         <small> -->
71 89
             @if($riga_ordine->piatto->elencoAllergeni->isNotEmpty())
@@ -76,6 +94,36 @@ $piatto = $riga_ordine->piatto??null;
76 94
         <!-- </small> -->
77 95
         @break
78 96
 
97
+
98
+        @case('colonna_action')
99
+
100
+            <small>
101
+                @if($riga_ordine->note)
102
+                    <span class="text-muted small">{{ $riga_ordine->note }}</span>
103
+                @else
104
+                <span class="text-muted small fst-italic">—</span>
105
+                @endif
106
+
107
+                @if($riga_ordine->quantita > 1)
108
+                <button title="Aggiungi variante" class="btn-expand-hover btn btn-primary mt-1" style="padding:revert;" onclick="aggiungiVariante({{ $piatto_id }}, {{ $riga_ordine_id }})" data-action="aggiungi_variante" data-piatto-id="{{ $piatto_id }}" data-riga-ordine-id="{{ $riga_ordine_id }}">
109
+                    <i class="bx bx-category-alt me-1" aria-label="Variante"></i>
110
+                    <span class="btn-expand-label">variante</span>
111
+                </button>
112
+                @endif
113
+                <button 
114
+                title="Elimina dal carrello"
115
+                    class="btn-expand-hover btn btn-danger mt-1"
116
+                    style="padding:revert;"
117
+                    onclick="eliminaRiga({{ $piatto->id }}, {{ $riga_ordine_id }})" 
118
+                    data-action="elimina" data-piatto-id="{{ $piatto->id }}" data-riga-ordine-id="{{ $riga_ordine_id }}">
119
+                    <i class="bx bx-trash"></i>
120
+                    <span class="btn-expand-label">elimina</span>
121
+                </button>
122
+
123
+            </small>
124
+
125
+        @break
126
+
79 127
     @case('note')
80 128
         @if($riga_ordine && $riga_ordine->note)
81 129
             <span class="text-muted small">{{ $riga_ordine->note }}</span>
@@ -85,14 +133,25 @@ $piatto = $riga_ordine->piatto??null;
85 133
         @break
86 134
 
87 135
     @case('menu')
88
-    <button 
89
-        class="mb-4 details-control col col-sm-4 col-4 col-md-4 col-xl-4 col-xxl-4 btn btn-sm  align-items-center justify-content-center p-0" 
90
-        style="width: 32px; height: 32px;" 
91
-        data-action="menu" 
92
-        data-bs-toggle="collapse" data-bs-target="#accordionPopoutIcon-{{ $riga_ordine_id }}" aria-expanded="true" aria-controls="accordionPopoutIcon-{{ $riga_ordine_id }}"
93
-        >
94
-            <i class="bx fs-xlarge bx-chevron-down"></i>
95
-        </button>
136
+    
137
+<button 
138
+    title="Elimina dal carrello"
139
+    class="btn-expand-hover btn btn-danger mt-1"
140
+    style="padding:revert;"
141
+    onclick="eliminaRiga({{ $piatto->id }}, {{ $riga_ordine_id }})" 
142
+    data-action="elimina" data-piatto-id="{{ $piatto->id }}" data-riga-ordine-id="{{ $riga_ordine_id }}">
143
+    <i class="bx bx-trash"></i>
144
+    <span class="btn-expand-label">elimina</span>
145
+</button>
146
+<button 
147
+    class="mb-4 details-control col col-sm-4 col-4 col-md-4 col-xl-4 col-xxl-4 btn btn-sm  align-items-center justify-content-center p-0" 
148
+    style="width: 32px; height: 32px;" 
149
+    data-action="menu" 
150
+    data-bs-toggle="collapse" data-bs-target="#accordionPopoutIcon-{{ $riga_ordine_id }}" aria-expanded="true" aria-controls="accordionPopoutIcon-{{ $riga_ordine_id }}"
151
+    >
152
+        <i class="bx fs-xlarge bx-chevron-down"></i>
153
+</button>
154
+
96 155
     @break
97 156
 
98 157
     @case('dettagli')

+ 150
- 0
resources/views/punto_vendita/cassa/_partials/carrello/item.blade.php Datei anzeigen

@@ -0,0 +1,150 @@
1
+@php
2
+    $piatto = $riga_ordine->piatto;
3
+    $hasAllergeni = $piatto?->elencoAllergeni?->isNotEmpty() ?? false;
4
+    $allergeniLabel = $hasAllergeni
5
+        ? $piatto->elencoAllergeni->pluck('nome')->implode(', ')
6
+        : '';
7
+    $showActions = true; //!$riga_ordine->note || $riga_ordine->quantita > 1;
8
+@endphp
9
+
10
+{{-- Bozza v1: stepper | contenuto | prezzo --}}
11
+<div class="carrello-item ">
12
+
13
+    <div class="d-flex align-items-center gap-2">
14
+
15
+        {{-- Stepper quantità --}}
16
+        <div class="carrello-item-stepper d-flex flex-shrink-0 border rounded overflow-hidden bg-white"
17
+             role="group"
18
+             aria-label="Quantità">
19
+            <button type="button"
20
+                class="carrello-item-stepper-btn btn btn-warning rounded-0 border-0"
21
+                title="Diminuisci"
22
+                aria-label="Diminuisci quantità"
23
+                onclick="diminuisciQuantita({{ $piatto_id }}, {{ $riga_ordine_id }})"
24
+                data-action="diminuisci"
25
+                data-piatto-id="{{ $piatto_id }}"
26
+                data-riga-ordine-id="{{ $riga_ordine_id }}">
27
+                <i class="bx bx-minus"></i>
28
+            </button>
29
+            <span class="carrello-item-stepper-qty d-flex align-items-center justify-content-center bg-light fw-bold border-start border-end">
30
+                {{ $riga_ordine->quantita }}
31
+            </span>
32
+            <button type="button"
33
+                class="carrello-item-stepper-btn btn btn-success rounded-0 border-0"
34
+                title="Aumenta"
35
+                aria-label="Aumenta quantità"
36
+                onclick="aumentaQuantita({{ $piatto_id }}, {{ $riga_ordine_id }})"
37
+                data-action="aumenta"
38
+                data-piatto-id="{{ $piatto_id }}"
39
+                data-riga-ordine-id="{{ $riga_ordine_id }}">
40
+                <i class="bx bx-plus"></i>
41
+            </button>
42
+        </div>
43
+
44
+        {{-- Nome, note, azioni --}}
45
+        <div class="flex-grow-1 min-w-0 align-self-start">
46
+
47
+            <div class="d-flex align-items-center gap-1 min-w-0">
48
+                <span class="carrello-item-nome fw-semibold text-truncate">{{ $piatto->nome ?? '—' }}</span>
49
+                @if($hasAllergeni)
50
+                    <button type="button"
51
+                        class="carrello-item-allergeni-hint btn btn-link p-0 flex-shrink-0"
52
+                        title="Mostra allergeni"
53
+                        aria-label="Allergeni: {{ $allergeniLabel }}"
54
+                        onclick="Swal.fire({icon:'warning',title:'Allergeni',text:{!! json_encode($allergeniLabel) !!}})">
55
+                        <i class="bx bx-error-circle text-warning"></i>
56
+                    </button>
57
+                @endif
58
+            </div>
59
+
60
+            @if($riga_ordine->note)
61
+                <button type="button"
62
+                    class="carrello-item-nota-text carrello-item-nota-text--present btn btn-link p-0 mt-1 text-start text-truncate d-block w-100 rounded-1"
63
+                    title="Modifica nota"
64
+                    data-nota="{{ e($riga_ordine->note) }}"
65
+                    onclick="aggiungiNota({{ $piatto_id }}, {{ $riga_ordine_id }}, this.getAttribute('data-nota'), this.getAttribute('data-piatto-nome'))"
66
+                    data-action="aggiungi_nota"
67
+                    data-piatto-nome="{{ $piatto->nome }}"
68
+                    data-piatto-id="{{ $piatto_id }}"
69
+                    data-riga-ordine-id="{{ $riga_ordine_id }}">
70
+                    <i class="bx bx-arrow-back rotate-180 me-1"></i>{{ $riga_ordine->note }}
71
+                </button>
72
+            @endif
73
+
74
+<!--  -->
75
+            <div class="carrello-item-actions d-flex flex-wrap gap-1 mt-1">
76
+                    @if(!$riga_ordine->note)
77
+                        <button type="button"
78
+                            class="carrello-item-action-btn btn btn-outline-secondary btn-sm"
79
+                            title="Aggiungi nota"
80
+                            onclick="aggiungiNota({{ $piatto_id }}, {{ $riga_ordine_id }}, '', this.getAttribute('data-piatto-nome'))"
81
+                            data-action="aggiungi_nota"
82
+                            data-piatto-nome="{{ $piatto->nome }}"
83
+                            data-piatto-id="{{ $piatto_id }}"
84
+                            data-riga-ordine-id="{{ $riga_ordine_id }}">
85
+                            <i class="bx bx-note"></i>
86
+                            <span class="ms-1">nota</span>
87
+                        </button>
88
+                    @endif
89
+                    @if($riga_ordine->quantita)
90
+                        <button type="button"
91
+                            class="carrello-item-action-btn btn btn-outline-secondary btn-sm"
92
+                            title="Aggiungi variante"
93
+                            onclick="aggiungiVariante({{ $piatto_id }}, {{ $riga_ordine_id }}, this.getAttribute('data-piatto-nome'))"
94
+                            data-action="aggiungi_variante"
95
+                            data-piatto-nome="{{ $piatto->nome }}"
96
+                            data-piatto-id="{{ $piatto_id }}"
97
+                            data-riga-ordine-id="{{ $riga_ordine_id }}">
98
+                            <i class="bx bx-category-alt"></i>
99
+                            <span class="ms-1">variante</span>
100
+                        </button>
101
+                    @endif
102
+                </div>
103
+                <!--  -->
104
+                
105
+                
106
+                @if($riga_ordine->has_variante->isNotEmpty())
107
+                @foreach($riga_ordine->has_variante as $variante)
108
+                @if($variante->variante_id != null )
109
+                    <button type="button"
110
+                        class="carrello-item-variante-text carrello-item-variante-text--present btn btn-link p-0 mt-1 text-start text-truncate d-block w-100 rounded-1"
111
+                        title="{{ $variante->nota }}"
112
+                        onclick="eliminaVariante({{ $riga_ordine_id }}, {{ $variante->variante_id }})"
113
+                        data-action="elimina_variante"
114
+                        data-piatto-id="{{ $piatto_id }}"
115
+                        data-riga-ordine-id="{{ $riga_ordine_id }}">
116
+                        <i class="bx bx-trash"></i>
117
+                        <span class="ms-1">{{ $variante->variante_piatto->label ?? 'ND' }}
118
+                             @if($variante->variante_piatto->prezzo != null && $variante->variante_piatto->prezzo != 0)
119
+                                ({{ $variante->variante_piatto->prezzo }} €)
120
+                           
121
+                             @endif
122
+                            </span>
123
+                    </button>
124
+                    @endif
125
+                    @endforeach
126
+                @endif
127
+
128
+        </div>
129
+
130
+        {{-- Prezzo e elimina --}}
131
+        <div class="d-flex flex-column align-items-center flex-shrink-0 gap-0 align-self-start">
132
+            <span class="carrello-item-prezzo fw-bold text-nowrap">
133
+                € {{ number_format($riga_ordine->prezzo, 2, ',', '.') }}
134
+            </span>
135
+            <button type="button"
136
+                class="carrello-item-delete btn btn-link text-danger p-0 d-flex flex-column align-items-center"
137
+                title="Elimina dal carrello"
138
+                aria-label="Elimina dal carrello"
139
+                onclick="eliminaRiga({{ $piatto_id }}, {{ $riga_ordine_id }})"
140
+                data-action="elimina"
141
+                data-piatto-id="{{ $piatto_id }}"
142
+                data-riga-ordine-id="{{ $riga_ordine_id }}">
143
+                <i class="bx bx-trash"></i>
144
+                <span class="carrello-item-delete-label">Elimina</span>
145
+            </button>
146
+        </div>
147
+
148
+    </div>
149
+
150
+</div>

+ 248
- 5
resources/views/punto_vendita/cassa/_partials/scripts.blade.php Datei anzeigen

@@ -87,26 +87,37 @@ function eliminaRiga(piattoId, rigaOrdineId) {
87 87
         }
88 88
     });
89 89
 }
90
-function aggiungiNota(piattoId, rigaOrdineId, nota) {
90
+function aggiungiNota(piattoId, rigaOrdineId, nota, piattoNome) {
91 91
     Swal.fire({
92 92
         title: "Aggiungi nota",
93
-        text: "Inserisci la nota per il piatto",
93
+        text: piattoNome != null ? "Nota per " + piattoNome : "Inserisci la nota",
94 94
         input: "text",
95 95
         inputValue: nota,
96 96
         inputPlaceholder: "Inserisci la nota",
97 97
         icon: "info",
98 98
         showCancelButton: true,
99
-        confirmButtonText: "Aggiungi",
99
+        confirmButtonText: "Salva",
100
+        denyButtonText: "Elimina",
101
+        showDenyButton: true,
100 102
         cancelButtonText: "Annulla",
103
+        customClass: {
104
+           confirmButton: "btn btn-primary",
105
+           denyButton: "btn btn-danger",
106
+           cancelButton: "btn btn-secondary",
107
+        },
101 108
         preConfirm: (value) => {
102 109
             return value; // qui puoi validare il valore se necessario
103 110
         }
111
+   
104 112
     }).then(function(result) {
105 113
         if (result.isConfirmed) {
106 114
             // Qui recuperi il valore dell'input
107 115
             var nota = result.value;
108 116
             aggiornaNota(piattoId, rigaOrdineId, nota);
109 117
         }
118
+        if(result.isDenied) {
119
+          aggiornaNota(piattoId, rigaOrdineId, null);
120
+        }
110 121
     });
111 122
 }
112 123
 function aggiornaNota(piattoId, rigaOrdineId, nota) {
@@ -123,7 +134,8 @@ function aggiornaNota(piattoId, rigaOrdineId, nota) {
123 134
             if(response.success){
124 135
                 new Notyf({
125 136
                     duration: 2000,
126
-                    position: { x: 'right', y: 'top' }
137
+                    position: { x: 'right', y: 'top' },
138
+                    ripple: false,
127 139
                 }).success(response.message);
128 140
                 aggiornaCarrello();
129 141
             }
@@ -131,12 +143,243 @@ function aggiornaNota(piattoId, rigaOrdineId, nota) {
131 143
         error: function(xhr, status, error) {
132 144
             new Notyf({
133 145
                 duration: 2000,
134
-                position: { x: 'right', y: 'top' }
146
+                position: { x: 'right', y: 'top' },
147
+                ripple: false,
135 148
             }).error(xhr.responseText);
136 149
         }
137 150
     });
138 151
 }
139 152
 
153
+function getVariantiPiatto(rigaOrdineId) {
154
+  var result = null;
155
+  $.ajax({
156
+    url: "{{ route('variante-piatto.list') }}",
157
+    type: "GET",
158
+    async: false,
159
+    data: {
160
+      riga_ordine_id: rigaOrdineId,
161
+    },
162
+    success: function(response) {
163
+      result = response;
164
+    },
165
+    error: function(xhr, status, error) {
166
+      console.log(xhr.responseText);
167
+    }
168
+  });
169
+  return result;
170
+}
171
+
172
+function eliminaVariante(rigaOrdineId, varianteId) {
173
+  $.ajax({
174
+    url: "{{ route('carrello.elimina-variante') }}",
175
+    type: "POST",
176
+    data: {
177
+      riga_ordine_id: rigaOrdineId,
178
+      variante_id: varianteId,
179
+      _token: "{{ csrf_token() }}",
180
+    },
181
+    success: function(response) {
182
+      if(response.success){
183
+        new Notyf({
184
+          duration: 2000,
185
+          position: { x: 'right', y: 'top' }
186
+        }).success(response.message);
187
+        aggiornaCarrello();
188
+      }
189
+    },
190
+    error: function(xhr, status, error) {
191
+      new Notyf({
192
+        duration: 2000,
193
+        position: { x: 'right', y: 'top' }
194
+      }).error(xhr.responseText);
195
+    }
196
+  });
197
+}
198
+
199
+
200
+function aggiungiVariante(piattoId, rigaOrdineId, piattoNome, nota, cucinaId) { 
201
+nota = null;
202
+  var varianti = getVariantiPiatto(rigaOrdineId);
203
+  if (!varianti) {
204
+  varianti = { variantiCucina: [], variantiPiatto: [] };
205
+}
206
+
207
+  var html = '';
208
+
209
+if (varianti.variantiCucina.length > 0) {
210
+  html += '<h4>Varianti cucina</h4><div class="d-flex flex-wrap gap-2 mb-2">';
211
+  varianti.variantiCucina.forEach(function (v) {
212
+    html += '<span class="variante-chip" data-id="' + v.id + '" data-label="' + v.label + '" style="display:inline-block;padding:6px 10px;border-radius:999px;border:1px solid #0d6efd;cursor:pointer;background:#fff;color:#0d6efd;">' +
213
+      v.label + ' (' + (v.prezzo ?? '0.00') + ' €)</span>';
214
+  });
215
+  html += '</div>';
216
+}
217
+
218
+if (varianti.variantiPiatto.length > 0) {
219
+  html += '<h4>Varianti piatto</h4><div class="d-flex flex-wrap gap-2 mb-2">';
220
+  varianti.variantiPiatto.forEach(function (v) {
221
+    html += '<span class="variante-chip" data-id="' + v.id + '" data-label="' + v.label + '" style="display:inline-block;padding:6px 10px;border-radius:999px;border:1px solid #0d6efd;cursor:pointer;background:#fff;color:#0d6efd;">' +
222
+      v.label + ' (' + (v.prezzo ?? '0.00') + ' €)</span>';
223
+  });
224
+  html += '</div>';
225
+}
226
+
227
+html += '<h4>Nota</h4>';
228
+html += '<input id="swal-variante-nota" class="form-control" value="' + (nota || '') + '">';
229
+
230
+  Swal.fire({
231
+    title: "Variante",
232
+    text: "Variazione per "+piattoNome,
233
+    icon: "question",
234
+    html: html,
235
+    showCloseButton: true,
236
+    showCancelButton: true,
237
+    cancelButtonText: "Annulla",
238
+    confirmButtonText: "Aggiungi varianti selezionate",
239
+    showDenyButton: false,
240
+    denyButtonText: "Dividi l'ordine in singoli piatti (tutti con questa nota)",
241
+    customClass: {
242
+      confirmButton: "btn btn-success",
243
+      denyButton: "btn btn-primary",
244
+      cancelButton: "btn btn-secondary",
245
+    },
246
+    preDeny: function () {
247
+  return this.preConfirm ? this.preConfirm() : null;
248
+},
249
+    preConfirm: function () {
250
+  const root = Swal.getHtmlContainer();
251
+  const selected = root ? root.querySelector('.variante-chip.is-selected') : null;
252
+  const notaInput = root ? root.querySelector('#swal-variante-nota') : null;
253
+
254
+  const varianteId = selected ? selected.getAttribute('data-id') : null;
255
+  const varianteLabel = selected ? selected.getAttribute('data-label') : '';
256
+  const notaLibera = notaInput ? notaInput.value.trim() : '';
257
+  const notaFinale = [varianteLabel, notaLibera].filter(Boolean).join(' - ');
258
+
259
+  return {
260
+    variante_id: varianteId,
261
+    nota: notaFinale
262
+  };
263
+},
264
+    didOpen: function () {
265
+  const root = Swal.getHtmlContainer();
266
+  if (!root) return;
267
+
268
+  root.querySelectorAll('.variante-chip').forEach(function (chip) {
269
+    chip.addEventListener('click', function () {
270
+      root.querySelectorAll('.variante-chip').forEach(function (c) {
271
+        c.classList.remove('is-selected');
272
+        c.style.background = '#fff';
273
+        c.style.color = '#0d6efd';
274
+      });
275
+      chip.classList.add('is-selected');
276
+      chip.style.background = '#0d6efd';
277
+      chip.style.color = '#fff';
278
+
279
+    });
280
+  });
281
+},
282
+
283
+  }).then((result) => {
284
+    const payload = result.value || {};
285
+    if (result.isConfirmed) {
286
+      $.ajax({
287
+    url: "{{ route('carrello.aggiungi-variante') }}",
288
+    type: "POST",
289
+    async: false,
290
+    data: {
291
+      tipo:  'singolo',
292
+      piatto_id: piattoId,
293
+      riga_ordine_id: rigaOrdineId,
294
+      _token: "{{ csrf_token() }}",
295
+      variante_id: payload.variante_id,
296
+nota: payload.nota,
297
+    },
298
+    success: function(response) {
299
+      if(response.success){
300
+        new Notyf({
301
+          duration: 2000,
302
+          position: { x: 'right', y: 'top' }
303
+        }).success(response.message);
304
+        aggiornaCarrello();
305
+      } else {
306
+        new Notyf({
307
+          duration: 2000,
308
+          position: { x: 'right', y: 'top' }
309
+        }).error(response.message);
310
+      }
311
+    },
312
+    error: function(xhr, status, error) {
313
+      new Notyf({
314
+        duration: 2000,
315
+        position: { x: 'right', y: 'top' }
316
+      }).error(xhr.responseJSON.message);
317
+    }
318
+  });
319
+    } else if (result.isDenied) {
320
+      $.ajax({
321
+    url: "{{ route('carrello.aggiungi-variante') }}",
322
+    type: "POST",
323
+    async: false,
324
+    data: {
325
+      tipo:  'tutti',
326
+      piatto_id: piattoId,
327
+      riga_ordine_id: rigaOrdineId,
328
+      variante_id: payload.variante_id,
329
+nota: payload.nota,
330
+      _token: "{{ csrf_token() }}",
331
+    },
332
+    success: function(response) {
333
+      if(response.success){
334
+        new Notyf({
335
+          duration: 2000,
336
+          position: { x: 'right', y: 'top' }
337
+        }).success(response.message);
338
+        aggiornaCarrello();
339
+      } else {
340
+        new Notyf({
341
+          duration: 2000,
342
+          position: { x: 'right', y: 'top' }
343
+        }).error(response.message);
344
+      }
345
+    },
346
+    error: function(xhr, status, error) {
347
+      new Notyf({
348
+        duration: 2000,
349
+        position: { x: 'right', y: 'top' }
350
+      }).error(xhr.responseJSON.message);
351
+    }
352
+  });
353
+    }
354
+    // Se annullato non fai nulla
355
+  });
356
+}
357
+
358
+function aggiungiVariantePiatto(tipo, piattoId, rigaOrdineId) {
359
+  $.ajax({
360
+    url: "{{ route('carrello.aggiungi-variante') }}",
361
+    type: "POST",
362
+    async: false,
363
+    data: {
364
+      tipo:  tipo,
365
+      piatto_id: piattoId,
366
+      riga_ordine_id: rigaOrdineId,
367
+      _token: "{{ csrf_token() }}",
368
+      success: function(response) {
369
+        if(response.success){
370
+          result = response;
371
+        }else{
372
+          result = false;
373
+        }
374
+      },
375
+      error: function(xhr, status, error) {
376
+        throw new Error(xhr.responseJSON.message);
377
+      }
378
+    },
379
+  });
380
+  return result;
381
+}
382
+
140 383
 function aggiornaCarrello() {
141 384
 
142 385
     // window.LaravelDataTables["dataTable_rigaordine"].ajax.reload()

+ 187
- 37
resources/views/punto_vendita/cassa/index.blade.php Datei anzeigen

@@ -144,6 +144,128 @@ html:has(.cassa-front-page) body {
144 144
 .cassa-cart-scroll .dataTables_info{
145 145
   padding-top: 0.35rem;
146 146
 }
147
+/* Riga carrello — bozza v1: stepper | contenuto | prezzo */
148
+.carrello-item {
149
+  padding: 0.75rem 0.25rem;
150
+  touch-action: manipulation;
151
+}
152
+.carrello-item-nome {
153
+  font-size: 1rem;
154
+  line-height: 1.3;
155
+}
156
+.carrello-item-prezzo {
157
+  font-size: 1.05rem;
158
+  color: var(--bs-primary);
159
+}
160
+.carrello-item-nota-text {
161
+  font-size: 0.85rem;
162
+  color: var(--bs-secondary-color);
163
+  text-decoration: none;
164
+}
165
+.carrello-item-nota-text--present {
166
+  color: var(--bs-warning-text-emphasis, var(--bs-warning));
167
+  background: rgba(var(--bs-warning-rgb), 0.1);
168
+  border-left: 3px solid var(--bs-warning);
169
+  border-radius: 0 0.25rem 0.25rem 0;
170
+  padding: 0.25rem 0.4rem 0.25rem 0.5rem !important;
171
+  margin-left: 0;
172
+}
173
+.carrello-item-nota-text:hover,
174
+.carrello-item-nota-text:focus-visible {
175
+  color: var(--bs-warning);
176
+  /* text-decoration: underline; */
177
+}
178
+.carrello-item-nota-text--present:hover,
179
+.carrello-item-nota-text--present:focus-visible {
180
+  background: rgba(var(--bs-warning-rgb), 0.16);
181
+}
182
+
183
+/*Varianti piatto*/
184
+.carrello-item-variante-text {
185
+  font-size: 0.85rem;
186
+  color: var(--bs-success-text-emphasis, var(--bs-success));
187
+  text-decoration: none;
188
+}
189
+.carrello-item-variante-text--present {
190
+  color: var(--bs-success-text-emphasis, var(--bs-success));
191
+  background: rgba(var(--bs-success-rgb), 0.1);
192
+  border-left: 3px solid var(--bs-success);
193
+  border-radius: 0 0.25rem 0.25rem 0;
194
+  padding: 0.25rem 0.4rem 0.25rem 0.5rem !important;
195
+  margin-left: 0;
196
+}
197
+.carrello-item-variante-text:hover,
198
+.carrello-item-variante-text:focus-visible {
199
+  color: var(--bs-success);
200
+  /* text-decoration: underline; */
201
+}
202
+.carrello-item-variante-text--present:hover,
203
+.carrello-item-variante-text--present:focus-visible {
204
+  background: rgba(var(--bs-success-rgb), 0.16);
205
+}
206
+
207
+.carrello-item-stepper-btn {
208
+  display: flex;
209
+  align-items: center;
210
+  justify-content: center;
211
+  width: 36px;
212
+  height: 40px;
213
+  min-width: 36px;
214
+  min-height: 40px;
215
+  padding: 0;
216
+  font-size: 1.2rem;
217
+  line-height: 1;
218
+}
219
+.carrello-item-stepper-qty {
220
+  min-width: 2.5rem;
221
+  height: 40px;
222
+  font-size: 1.2rem;
223
+  font-weight: 800;
224
+  font-variant-numeric: tabular-nums;
225
+  color: var(--bs-primary);
226
+}
227
+.carrello-item-action-btn {
228
+  font-size: 0.8rem;
229
+}
230
+.carrello-item-actions:empty {
231
+  display: none !important;
232
+}
233
+.carrello-item-delete {
234
+  min-width: 44px;
235
+  min-height: 44px;
236
+  font-size: 1.15rem;
237
+  line-height: 1;
238
+  text-decoration: none;
239
+  gap: 0.1rem;
240
+}
241
+.carrello-item-delete-label {
242
+  font-size: 0.65rem;
243
+  font-weight: 600;
244
+  line-height: 1;
245
+  text-transform: uppercase;
246
+  letter-spacing: 0.02em;
247
+}
248
+.carrello-item-delete:hover,
249
+.carrello-item-delete:focus-visible {
250
+  opacity: 0.85;
251
+  text-decoration: none;
252
+}
253
+.carrello-item-allergeni-hint {
254
+  line-height: 1;
255
+  text-decoration: none;
256
+}
257
+.carrello-item-stepper-btn:active,
258
+.carrello-item-delete:active,
259
+.carrello-item-action-btn:active,
260
+.carrello-item-nota-text:active,
261
+.carrello-item-variante-text:active {
262
+  transform: scale(0.97);
263
+}
264
+.cassa-cart-scroll table.dataTable tbody td {
265
+  padding-top: 0;
266
+  padding-bottom: 0;
267
+  vertical-align: top;
268
+}
147 269
 .cassa-footer{
148 270
   flex-shrink: 0;
149 271
   margin-top: 0.25rem !important;
@@ -160,6 +282,33 @@ html:has(.cassa-front-page) body {
160 282
     max-height: none;
161 283
   }
162 284
 }
285
+/* Base: icona + testo in fila */
286
+.btn-expand-hover {
287
+  display: inline-flex;
288
+  align-items: center;
289
+  gap: 0;
290
+  overflow: hidden;
291
+  white-space: nowrap;
292
+  transition: padding 0.2s ease;
293
+}
294
+
295
+/* Testo nascosto di default (tutte le dimensioni) */
296
+.btn-expand-hover .btn-expand-label {
297
+  display: inline-block;
298
+  max-width: 0;
299
+  opacity: 0;
300
+  overflow: hidden;
301
+  transition: max-width 0.25s ease, opacity 0.2s ease, margin-left 0.25s ease;
302
+  margin-left: 0;
303
+}
304
+
305
+/* Hover/focus: espande e mostra il testo */
306
+.btn-expand-hover:hover .btn-expand-label,
307
+.btn-expand-hover:focus-visible .btn-expand-label {
308
+  max-width: 6rem;
309
+  opacity: 1;
310
+  margin-left: 0.35rem;
311
+}
163 312
 </style>
164 313
 
165 314
 <div class="container-fluid cassa-front-page px-2 px-md-3 px-xl-3">
@@ -179,42 +328,43 @@ html:has(.cassa-front-page) body {
179 328
       </h4>
180 329
     </div>    
181 330
     
182
-    <div class="align-content-center col-4 gap-x-2">
183
-      @if(Auth::guard('operatore')->check())
184
-      <a href="{{ route('operatore.dashDispositivi') }}" class="ms-2 px-3 py-1 alert text-bg-primary"> <!-- btn btn-primary -->
185
-        <i class="bx bx-category"></i>
186
-        Dashboard
187
-      </a>
188
-      @elseif(Auth::guard('web')->check())
189
-      <a href="{{ route('dashboard') }}" class="ms-2 px-3 py-1 alert text-bg-secondary"> <!-- btn btn-primary -->
190
-        <i class="bx bx-category"></i>
191
-        Dashboard
192
-      </a>
193
-      
194
-      <a href="{{ route('profile.show') }}" class="ms-2 px-3 py-1 alert text-bg-secondary"> <!-- btn btn-primary -->
195
-        <i class="bx bx-user-circle mx-1"></i>
196
-        {{ Auth::user()->fullName()}}
197
-      </a>
198
-      @endif
199
-
200
-      @if($punto_vendita->binding_token)
201
-        <span class="px-3 py-1 alert alert-success ms-2"> 
202
-          <i class="bx bx-link"></i>
203
-          <!-- Linked -->
204
-        </span>
205
-      @endif
206
-
207
-      <span class="dropdown">
208
-            <button class="btn text-muted p-0" type="button" id="transactionID" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
209
-              <i class="bx bx-menu bx-lg text-primary fs-2"></i> <!-- bx-dots-vertical-rounded-->
210
-            </button>
211
-            <div class="dropdown-menu dropdown-menu-end" aria-labelledby="transactionID">
212
-              <a class="dropdown-item" href="javascript:void(0);" onclick="showInfoPuntoVendita()">Informazioni punto vendita</a>
213
-              <!-- <a class="dropdown-item" href="javascript:void(0);" onclick="stampaRiepilogo()">Stampa riepilogo</a> -->
214
-              <a class="dropdown-item" href="javascript:void(0);" onclick="dissociaDispositivo()">Dissocia dispositivo</a>
215
-              <!-- <a class="dropdown-item" href="javascript:void(0);" onclick="chiudiPuntoVendita(alert('Chiudi {{ $punto_vendita->tipo}}'))">Chiudi {{ $punto_vendita->tipo}}</a> -->
216
-            </div>
217
-          </span>
331
+    <div class="col-4 d-flex align-items-center justify-content-end">
332
+      <div class="dropdown">
333
+        <button class="btn btn-sm btn-outline-secondary d-flex align-items-center" type="button" id="transactionID" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
334
+          <i class="bx bx-menu fs-5"></i>
335
+        </button>
336
+        <div class="dropdown-menu dropdown-menu-end" aria-labelledby="transactionID">
337
+          @if(Auth::guard('operatore')->check())
338
+            <a class="dropdown-item" href="{{ route('operatore.dashDispositivi') }}">
339
+              <i class="bx bx-category me-2"></i>Dashboard
340
+            </a>
341
+          @elseif(Auth::guard('web')->check())
342
+            <a class="dropdown-item" href="{{ route('dashboard') }}">
343
+              <i class="bx bx-category me-2"></i>Dashboard
344
+            </a>
345
+          @endif
346
+          @if(Auth::guard('web')->check())
347
+            <a class="dropdown-item" href="{{ route('profile.show') }}">
348
+              <i class="bx bx-user-circle me-2"></i>{{ Auth::user()->fullName() }}
349
+            </a>
350
+          @endif
351
+          @if($punto_vendita->binding_token)
352
+            <span class="dropdown-item-text text-success">
353
+              <i class="bx bx-link me-2"></i>Linker attivo
354
+            </span>
355
+          @endif
356
+          <a class="dropdown-item" href="{{ route('punto-vendita.show', ['punto_vendita_id' => $punto_vendita->id , 'vista' => 'catalogo']) }}">
357
+            <i class="bx bx-list-ul me-2"></i>Vista catalogo
358
+          </a>
359
+          <div class="dropdown-divider"></div>
360
+          <a class="dropdown-item" href="javascript:void(0);" onclick="showInfoPuntoVendita()">
361
+            <i class="bx bx-info-circle me-2"></i>Informazioni punto vendita
362
+          </a>
363
+          <a class="dropdown-item text-danger" href="javascript:void(0);" onclick="dissociaDispositivo()">
364
+            <i class="bx bx-unlink me-2"></i>Dissocia dispositivo
365
+          </a>
366
+        </div>
367
+      </div>
218 368
 
219 369
       <a href="{{ route('punto-vendita.show', ['punto_vendita_id' => $punto_vendita->id , 'vista' => 'catalogo']) }}" class=" d-none ms-2 px-3 py-1 alert text-bg-primary"> <!-- btn btn-primary -->
220 370
         <i class="bx bx-list-ul mx-1"></i>
@@ -270,7 +420,7 @@ html:has(.cassa-front-page) body {
270 420
           @include('punto_vendita.cassa._partials.carrello.riepilogo')
271 421
         </div>
272 422
         <div class="card-body pt-0 pb-2 text-start cassa-cart-scroll">
273
-          {{ $dataTable_rigaordine->table() }}
423
+          {{ $dataTable_rigaordine->table(['class' => 'table-borderless table']) }}
274 424
           <!-- @foreach($ordine->righe_ordine as $riga_ordine)
275 425
             @include('punto_vendita.cassa._partials.carrello.righe_ordine' , ['riga_ordine' => $riga_ordine])
276 426
           @endforeach -->

+ 9
- 0
resources/views/variante_piatto/datatable.blade.php Datei anzeigen

@@ -0,0 +1,9 @@
1
+
2
+
3
+
4
+<div class="card-body pt-0">
5
+        {{ $dataTable_variante_piatto->table(['class' => 'table table-bordered']) }}
6
+      </div>
7
+
8
+
9
+ @include('variante_piatto.datatable_script') 

+ 55
- 0
resources/views/variante_piatto/datatable_script.blade.php Datei anzeigen

@@ -0,0 +1,55 @@
1
+
2
+
3
+{{$dataTable_variante_piatto->scripts(attributes: ['type' => 'module'])}}
4
+
5
+
6
+<script type="module">
7
+  $(document).ready(function(){
8
+    // Editor edit
9
+    $("#dataTable_variante_piatto").on('click', 'a.editor_edit', function (e) {
10
+      e.preventDefault();
11
+      window.LaravelDataTables["dataTable_variante_piatto-editor"].edit( $(this).closest('tr'), {
12
+        title: 'Modifica',
13
+        buttons: 'Aggiorna',
14
+      });
15
+    });
16
+
17
+    // Editor delete
18
+    $("#dataTable_variante_piatto").on('click', 'a.editor_delete', function (e) {
19
+      e.preventDefault();
20
+      window.LaravelDataTables["dataTable_variante_piatto-editor"].remove($(this).closest('tr'), {
21
+        title: 'Cancella record',
22
+        message: 'Sei sicuro di voler eliminare il record selezionato?',
23
+        buttons: 'Cancella record'
24
+      });
25
+    } );
26
+
27
+    $("#dataTable_variante_piatto").on('dblclick', 'tbody td', function (e) {
28
+      window.LaravelDataTables["dataTable_variante_piatto-editor"].edit( $(this).closest('tr'), {
29
+        title: 'Modifica',
30
+        buttons: 'Aggiorna',
31
+      });
32
+    });
33
+
34
+  });
35
+
36
+</script>
37
+
38
+<script>
39
+  function initComplete_variante_piatto(){
40
+    $('div.dt-buttons button').removeClass('btn-secondary');
41
+    $('div.dt-search').addClass('mt-0 mb-4');
42
+    $('div.btn-group').removeClass('btn-group');
43
+    return;
44
+  }
45
+
46
+  function aggiornaVariantePiattoDataTable(categoria_id) {
47
+  const dt = window.LaravelDataTables["dataTable_variante_piatto"];
48
+  dt.settings()[0].ajax.data = function(d) {
49
+    d.cucina_id = cucina_id;
50
+  };
51
+  dt.ajax.reload();
52
+}
53
+
54
+
55
+</script>

+ 23
- 0
resources/views/variante_piatto/menu.blade.php Datei anzeigen

@@ -0,0 +1,23 @@
1
+<?php
2
+use Illuminate\Support\Facades\Auth;
3
+?>
4
+
5
+<div class="dropdown">
6
+    <button type="button" class="btn p-0 dropdown-toggle hide-arrow" data-bs-toggle="dropdown" aria-expanded="false">
7
+        <i class="bx bx-dots-vertical-rounded fs-large"></i>
8
+    </button>
9
+    <div class="dropdown-menu">
10
+
11
+        @if(Auth::user()->can('edit-variante-piatto'))
12
+        <a href="#" class="dropdown-item editor_edit">
13
+            <i class="bx bx-edit-alt me-1"></i> Modifica
14
+        </a>
15
+        @endif
16
+
17
+        @if(Auth::user()->can('delete-variante-piatto'))
18
+        <a href="#" class="dropdown-item editor_delete text-danger">
19
+            <i class="bx bx-trash me-1 text-danger"></i> Elimina
20
+        </a>
21
+        @endif
22
+    </div>
23
+</div>

+ 17
- 7
routes/web.php Datei anzeigen

@@ -43,6 +43,7 @@ use App\Http\Controllers\OperatoreController;
43 43
 use App\Http\Controllers\TombolaController;
44 44
 use App\Http\Controllers\ChiusuraServizioController;
45 45
 use App\Http\Controllers\ImpostazioniController;
46
+use App\Http\Controllers\VariantePiattoController;
46 47
 
47 48
 Route::get('/', [HomePageController::class, 'welcome'])->name('welcome');
48 49
 
@@ -85,7 +86,20 @@ Route::middleware(['auth:sanctum', AttivitaMiddleware::class, config('jetstream.
85 86
   
86 87
   // Cucina
87 88
   Route::resource('cucina', CucinaController::class, ['only' => ['index', 'store']]);
89
+  Route::get('cucina/dashboard', [CucinaController::class, 'dashboard'])->name('cucina.dashboard');
88 90
   
91
+  // Piatto
92
+  Route::resource('piatto', PiattoController::class, ['only' => ['index', 'store']]);
93
+  Route::get('piatto/datatable', [PiattoController::class, 'datatable'])->name('piatto.datatable');
94
+  
95
+  // Variante Piatto
96
+  Route::resource('variante-piatto', VariantePiattoController::class, ['only' => ['index', 'store']])->names(['index' => 'variante-piatto.index', 'store' => 'variante-piatto.store']);
97
+  Route::get('variante-piatto/datatable', [VariantePiattoController::class, 'datatable'])->name('variante-piatto.datatable');
98
+  Route::get('variante-piatto/list', [VariantePiattoController::class, 'list'])->name('variante-piatto.list');
99
+  
100
+  // Allergene
101
+  Route::resource('allergene', AllergeneController::class, ['only' => ['index', 'store']]);
102
+
89 103
   // Evento
90 104
   Route::resource('evento', EventoController::class, ['only' => ['index', 'store']]);
91 105
   Route::get('evento/gallery/edit', [EventoController::class, 'gallery_edit'])->name('evento.gallery.edit');
@@ -106,13 +120,6 @@ Route::middleware(['auth:sanctum', AttivitaMiddleware::class, config('jetstream.
106 120
   Route::get('prenotazione/show', [PrenotazioneController::class, 'show'])->name('prenotazione.show');
107 121
   Route::get('prenotazione/report/index', [PrenotazioneController::class, 'report_index'])->name('prenotazione.report.index');
108 122
   
109
-  // Piatto
110
-  Route::resource('piatto', PiattoController::class, ['only' => ['index', 'store']]);
111
-  Route::get('piatto/datatable', [PiattoController::class, 'datatable'])->name('piatto.datatable');
112
-  
113
-  // Allergene
114
-  Route::resource('allergene', AllergeneController::class, ['only' => ['index', 'store']]);
115
-  
116 123
   // Fornitore
117 124
   Route::resource('fornitore', FornitoreController::class, ['only' => ['index', 'store']]);
118 125
   Route::get('fornitore/show', [FornitoreController::class, 'show'])->name('fornitore.show');
@@ -206,12 +213,15 @@ Route::get('dashboard', [HomePageController::class, 'admin_dashboard'])->name('d
206 213
 
207 214
 // Carrello
208 215
 Route::get('carrello', [CarrelloController::class, 'index'])->name('carrello.index');
216
+//Azioni sul carrello
209 217
 Route::get('carrello/list', [CarrelloController::class, 'list'])->name('carrello.list');
210 218
 Route::post('carrello/aumenta', [CarrelloController::class, 'aumenta'])->name('carrello.aumenta');
211 219
 Route::post('carrello/diminuisci', [CarrelloController::class, 'diminuisci'])->name('carrello.diminuisci');
212 220
 Route::post('carrello/elimina', [CarrelloController::class, 'elimina'])->name('carrello.elimina');
213 221
 Route::post('carrello/aggiorna_nota', [CarrelloController::class, 'aggiorna_nota'])->name('carrello.aggiorna_nota');
214 222
 Route::post('carrello/azzera', [CarrelloController::class, 'azzera'])->name('carrello.azzera');
223
+Route::post('carrello/aggiungi-variante', [CarrelloController::class, 'aggiungi_variante'])->name('carrello.aggiungi-variante');
224
+Route::post('carrello/elimina-variante', [CarrelloController::class, 'elimina_variante'])->name('carrello.elimina-variante');
215 225
 Route::get('carrello/totale', [CarrelloController::class, 'totale'])->name('carrello.totale');
216 226
 Route::post('carrello/aggiorna_info', [CarrelloController::class, 'aggiorna_info'])->name('carrello.aggiorna_info');
217 227
 Route::get('carrello/checkout', [CarrelloController::class, 'checkout'])->name('carrello.checkout');

Laden…
Abbrechen
Speichern