ソースを参照

feat(piatti): add custom display order support

Co-authored-by: Cursor <cursoragent@cursor.com>
marcofalabretti 2週間前
コミット
480e1ee596

+ 11
- 3
app/DataTables/PiattoDataTable.php ファイルの表示

@@ -70,6 +70,11 @@ class PiattoDataTable extends DataTable
70 70
             ->addColumn('prezzo_display', function ($entity) {
71 71
                 return '€ ' . number_format($entity->prezzo, 2, ',', '.');
72 72
             })
73
+            ->addColumn('ordine_visualizzazione_display', function ($entity) {
74
+                return Piatto::ordineVisualizzazioneImpostato($entity->ordine_visualizzazione)
75
+                    ? (string) (int) $entity->ordine_visualizzazione
76
+                    : '';
77
+            })
73 78
             ->setRowId('id');
74 79
     }
75 80
 
@@ -89,10 +94,11 @@ class PiattoDataTable extends DataTable
89 94
 
90 95
         if (isset($this->cucina_id)) {
91 96
             return $model->where('cucina_id', $this->cucina_id)
92
-                ->with('cucina', 'elencoAllergeni');
97
+                ->with('cucina', 'elencoAllergeni')
98
+                ->ordinatiInCassa();
93 99
         }
94 100
 
95
-        return $model->with('cucina', 'elencoAllergeni');
101
+        return $model->with('cucina', 'elencoAllergeni')->ordinatiInCassa();
96 102
     }
97 103
 
98 104
     /**
@@ -146,9 +152,10 @@ class PiattoDataTable extends DataTable
146 152
                     ->ajax(route('piatto.store'))
147 153
                     ->fields([
148 154
                         Fields\Hidden::make('attivita_id')->label('Attività')->default((int) $this->attivita_id),
155
+                        Fields\Number::make('ordine_visualizzazione')->label('Ordine visualizzazione'),
149 156
                         Fields\Text::make('nome')->label('Nome'),
150 157
                         Fields\Text::make('descrizione')->label('Descrizione'),
151
-                        Fields\Select2::make('cucina_id')->label('cucina')
158
+                        Fields\Select2::make('cucina_id')->label('Cucina')
152 159
                         ->options(Cucina::where('is_attiva', true)->where('attivita_id', (int) $this->attivita_id)->pluck('id', 'nome'))
153 160
                         ->default(isset($this->cucina_id) ? $this->cucina_id : ''),
154 161
                         Fields\Text::make('prezzo')->label('Prezzo (€)'),
@@ -202,6 +209,7 @@ class PiattoDataTable extends DataTable
202 209
         $columns = array_merge($columns, [
203 210
 
204 211
             Column::make('nome')->title('Nome')->searchable()->responsivePriority(1),
212
+            Column::make('ordine_visualizzazione')->data('ordine_visualizzazione_display')->title('Ordine')->addClass('text-center')->width('8%'),
205 213
             Column::make('prezzo')->data('prezzo_display')->title('Prezzo')->addClass('text-center'),
206 214
             // Column::computed('cucina_id')->data('cucina_id_display')->title('Cucina')->addClass('text-center')->responsivePriority(2), // icona in tabella
207 215
             Column::make('allergeni')->title('Allergeni')->visible(false), // valore grezzo per l'editor (array ID)

+ 25
- 1
app/DataTables/PiattoDataTableEditor.php ファイルの表示

@@ -5,10 +5,13 @@ namespace App\DataTables;
5 5
 use App\Models\Cucina;
6 6
 use App\Models\Piatto;
7 7
 use App\Models\PiattoHasAllergene;
8
+use App\Models\RigaOrdine;
9
+use App\Models\SaltacodaRigaOrdine;
8 10
 use App\Services\Attivita\AttivitaService;
9 11
 use Illuminate\Database\Eloquent\Model;
10 12
 use Yajra\DataTables\DataTablesEditor;
11 13
 use Illuminate\Support\Facades\Session;
14
+use Illuminate\Validation\ValidationException;
12 15
 
13 16
 class PiattoDataTableEditor extends DataTablesEditor
14 17
 {
@@ -26,6 +29,7 @@ class PiattoDataTableEditor extends DataTablesEditor
26 29
     'bacheca_id.required' => 'Indicare una delle due opzioni',
27 30
     'in_evidenza.required' => 'Indicare una delle due opzioni',
28 31
     'cucina_id.required' => 'La cucina è richiesta',
32
+    'ordine_visualizzazione.required' => 'Per ordine alfabetico scrivi 0 altrimenti imposta posizione ',
29 33
   ];
30 34
 
31 35
   /**
@@ -46,6 +50,7 @@ class PiattoDataTableEditor extends DataTablesEditor
46 50
       'allergeni.*' => 'integer|exists:allergene,id',
47 51
       'bacheca_id' => 'nullable|boolean',
48 52
       'in_evidenza' => 'nullable|boolean',
53
+      'ordine_visualizzazione' => 'required|integer',
49 54
     ];
50 55
   }
51 56
 
@@ -72,6 +77,7 @@ class PiattoDataTableEditor extends DataTablesEditor
72 77
       'allergeni.*' => 'integer|exists:allergene,id',
73 78
       'bacheca_id' => 'nullable|boolean',
74 79
       'in_evidenza' => 'nullable|boolean',
80
+      'ordine_visualizzazione' => 'nullable|integer',
75 81
     ];
76 82
   }
77 83
 
@@ -104,6 +110,7 @@ class PiattoDataTableEditor extends DataTablesEditor
104 110
     $data['bacheca_id'] = isset($data['bacheca_id']) ? true : false;
105 111
     $data['in_evidenza'] = isset($data['in_evidenza']) ? true : false;
106 112
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
113
+    $data['ordine_visualizzazione'] = $this->normalizeOrdineVisualizzazione($data['ordine_visualizzazione'] ?? null);
107 114
     return $data;
108 115
   }
109 116
 
@@ -119,6 +126,7 @@ class PiattoDataTableEditor extends DataTablesEditor
119 126
     $data['bacheca_id'] = isset($data['bacheca_id']) ? true : false;
120 127
     $data['in_evidenza'] = isset($data['in_evidenza']) ? true : false;
121 128
     $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
129
+    $data['ordine_visualizzazione'] = $this->normalizeOrdineVisualizzazione($data['ordine_visualizzazione'] ?? null);
122 130
 
123 131
     return $data;
124 132
   }
@@ -127,7 +135,23 @@ class PiattoDataTableEditor extends DataTablesEditor
127 135
   {
128 136
     AttivitaService::garantisciAttivita($model->attivita_id);
129 137
 
130
-    return $data;
138
+      $usatoInOrdini = RigaOrdine::where('piatto_id', $model->id)->exists();
139
+      $usatoInSaltacoda = SaltacodaRigaOrdine::where('piatto_id', $model->id)->exists();
140
+        if ($usatoInOrdini || $usatoInSaltacoda) {
141
+            throw ValidationException::withMessages([
142
+                'piatto' => 'Non puoi eliminare questo piatto: è già presente in ordini o preordini. Modifica la disponiblità invece.',
143
+            ]);
144
+        }
145
+        return $data;
146
+  }
147
+
148
+  private function normalizeOrdineVisualizzazione(mixed $value): ?int
149
+  {
150
+    if ($value === null || $value === '' || (int) $value === 0) {
151
+      return null;
152
+    }
153
+
154
+    return (int) $value;
131 155
   }
132 156
 
133 157
   private function garantisciCucinaDiQuestaAttivita($cucinaId, $attivitaId): void

+ 2
- 0
app/Models/AbstractModels/AbstractPiatto.php ファイルの表示

@@ -47,6 +47,7 @@ abstract class AbstractPiatto extends \Illuminate\Foundation\Auth\User
47 47
         'allergeni' => 'string',
48 48
         'bacheca_id' => 'boolean',
49 49
         'in_evidenza' => 'boolean',
50
+        'ordine_visualizzazione' => 'integer',
50 51
         'created_at' => 'datetime',
51 52
         'updated_at' => 'datetime'
52 53
     ];
@@ -69,6 +70,7 @@ abstract class AbstractPiatto extends \Illuminate\Foundation\Auth\User
69 70
         'allergeni',
70 71
         'bacheca_id',
71 72
         'in_evidenza',
73
+        'ordine_visualizzazione',
72 74
         'created_at',
73 75
         'updated_at'
74 76
     ];

+ 37
- 0
app/Models/Piatto.php ファイルの表示

@@ -26,4 +26,41 @@ class Piatto extends \App\Models\AbstractModels\AbstractPiatto
26 26
             'allergene_id'
27 27
         );
28 28
     }
29
+
30
+    /**
31
+     * NULL e 0 = non impostato. Il cast integer trasforma NULL in 0 in lettura.
32
+     */
33
+    public static function ordineVisualizzazioneImpostato(mixed $valore): bool
34
+    {
35
+        return $valore !== null && $valore !== '' && (int) $valore !== 0;
36
+    }
37
+
38
+    public function scopeOrdinatiInCassa($query)
39
+    {
40
+        return $query
41
+            ->orderByRaw('(ordine_visualizzazione IS NULL OR ordine_visualizzazione = 0) ASC')
42
+            ->orderBy('ordine_visualizzazione')
43
+            ->orderBy('nome');
44
+    }
45
+
46
+    /**
47
+     * Tutti i piatti numerati → ordine in cassa. Altrimenti alfabetico.
48
+     */
49
+    public static function ordinaCollezioneInCassa($piatti)
50
+    {
51
+        $piatti = collect($piatti);
52
+        $tuttiNumerati = $piatti->isNotEmpty()
53
+            && $piatti->every(fn ($piatto) => static::ordineVisualizzazioneImpostato($piatto->ordine_visualizzazione));
54
+
55
+        if ($tuttiNumerati) {
56
+            return $piatti->sortBy([
57
+                ['ordine_visualizzazione', 'asc'],
58
+                ['nome', 'asc'],
59
+            ])->values();
60
+        }
61
+
62
+        return $piatti
63
+            ->sortBy(fn ($piatto) => mb_strtolower((string) ($piatto->nome ?? '')), SORT_NATURAL)
64
+            ->values();
65
+    }
29 66
 }

+ 31
- 0
database/migrations/2026_09_01_223138_add_ordine_visualizzazione_to_piatto_table.php ファイルの表示

@@ -0,0 +1,31 @@
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::table('piatto', function (Blueprint $table) {
15
+            $table->integer('ordine_visualizzazione')
16
+                ->default(0)
17
+                ->nullable()
18
+                ->after('in_evidenza');
19
+        });
20
+    }
21
+
22
+    /**
23
+     * Reverse the migrations.
24
+     */
25
+    public function down(): void
26
+    {
27
+        Schema::table('piatto', function (Blueprint $table) {
28
+            $table->dropColumn('ordine_visualizzazione');
29
+        });
30
+    }
31
+};

読み込み中…
キャンセル
保存