瀏覽代碼

Contabilità, Saltacoda, testi, cassa, report, et al.

marcofalabretti 1 月之前
父節點
當前提交
101cd4be9e
共有 100 個文件被更改,包括 4870 次插入120 次删除
  1. 2
    1
      .env
  2. 6
    2
      app/DataTables/AttivitaDataTable.php
  3. 116
    0
      app/DataTables/CategoriacontabileDataTable.php
  4. 93
    0
      app/DataTables/CategoriacontabileDataTableEditor.php
  5. 1
    0
      app/DataTables/ContenutoBachecaDataTable.php
  6. 3
    2
      app/DataTables/ContenutoBachecaDataTableEditor.php
  7. 1
    1
      app/DataTables/CucinaDataTable.php
  8. 159
    0
      app/DataTables/EventoFormDataTable.php
  9. 115
    0
      app/DataTables/EventoFormDataTableEditor.php
  10. 2
    1
      app/DataTables/FornitoreDataTable.php
  11. 6
    6
      app/DataTables/FornitoreDataTableEditor.php
  12. 11
    6
      app/DataTables/MonitorDataTable.php
  13. 118
    0
      app/DataTables/OpzioneFormDataTable.php
  14. 50
    0
      app/DataTables/OpzioneFormDataTableEditor.php
  15. 3
    0
      app/DataTables/OrdineDataTable.php
  16. 20
    5
      app/DataTables/PiattoDataTable.php
  17. 13
    4
      app/DataTables/PrenotazioneDataTable.php
  18. 138
    22
      app/DataTables/PrimaNotaDataTable.php
  19. 118
    0
      app/DataTables/PrimaNotaDataTableEditor.php
  20. 130
    0
      app/DataTables/PuntoOperatoreDataTable.php
  21. 114
    0
      app/DataTables/PuntoOperatoreDataTableEditor.php
  22. 109
    0
      app/DataTables/TestiDataTable.php
  23. 104
    0
      app/DataTables/TestiDataTableEditor.php
  24. 331
    1
      app/Http/Controllers/BilancioController.php
  25. 24
    6
      app/Http/Controllers/CarrelloController.php
  26. 53
    0
      app/Http/Controllers/CategoriaContabileController.php
  27. 41
    1
      app/Http/Controllers/ConsultaController.php
  28. 8
    0
      app/Http/Controllers/EndpointController.php
  29. 10
    0
      app/Http/Controllers/EventoController.php
  30. 59
    0
      app/Http/Controllers/EventoFormController.php
  31. 18
    1
      app/Http/Controllers/FornitoreController.php
  32. 127
    3
      app/Http/Controllers/MonitorController.php
  33. 57
    0
      app/Http/Controllers/OpzioneFormController.php
  34. 6
    0
      app/Http/Controllers/OrdineController.php
  35. 6
    5
      app/Http/Controllers/PagamentoController.php
  36. 72
    0
      app/Http/Controllers/PrenotazioneController.php
  37. 10
    0
      app/Http/Controllers/PrenotazioneRisposteController.php
  38. 1
    0
      app/Http/Controllers/PrimaNotaController.php
  39. 84
    0
      app/Http/Controllers/PuntoOperatoreController.php
  40. 101
    4
      app/Http/Controllers/PuntovenditaController.php
  41. 459
    0
      app/Http/Controllers/ReportController.php
  42. 190
    0
      app/Http/Controllers/RigaOrdineController.php
  43. 247
    0
      app/Http/Controllers/SaltacodaController.php
  44. 72
    0
      app/Http/Controllers/TestiController.php
  45. 9
    0
      app/Models/AbstractModels/AbstractAttivita.php
  46. 63
    0
      app/Models/AbstractModels/AbstractCategoriacontabile.php
  47. 17
    0
      app/Models/AbstractModels/AbstractDispositivo.php
  48. 67
    0
      app/Models/AbstractModels/AbstractDispositivoHasCucina.php
  49. 5
    0
      app/Models/AbstractModels/AbstractEvento.php
  50. 99
    0
      app/Models/AbstractModels/AbstractEventoForm.php
  51. 7
    0
      app/Models/AbstractModels/AbstractFornitore.php
  52. 84
    0
      app/Models/AbstractModels/AbstractMonitorHasContenuto.php
  53. 73
    0
      app/Models/AbstractModels/AbstractOpzioneEvento.php
  54. 8
    0
      app/Models/AbstractModels/AbstractPrenotazione.php
  55. 78
    0
      app/Models/AbstractModels/AbstractPrenotazioneRisposta.php
  56. 0
    4
      app/Models/AbstractModels/AbstractPrimaNota.php
  57. 2
    0
      app/Models/AbstractModels/AbstractRigaOrdine.php
  58. 70
    0
      app/Models/AbstractModels/AbstractSaltacoda.php
  59. 89
    0
      app/Models/AbstractModels/AbstractSaltacodaOrdine.php
  60. 75
    0
      app/Models/AbstractModels/AbstractSaltacodaRigaordine.php
  61. 79
    0
      app/Models/AbstractModels/AbstractTesti.php
  62. 1
    1
      app/Models/BachecaHasContenuto.php
  63. 10
    0
      app/Models/Categoriacontabile.php
  64. 17
    0
      app/Models/Dispositivo.php
  65. 10
    0
      app/Models/DispositivoHasCucina.php
  66. 60
    0
      app/Models/EventoForm.php
  67. 8
    1
      app/Models/MetodoPagamento.php
  68. 10
    0
      app/Models/MonitorHasContenuto.php
  69. 10
    0
      app/Models/OpzioneForm.php
  70. 37
    15
      app/Models/Prenotazione.php
  71. 10
    0
      app/Models/PrenotazioneRisposta.php
  72. 5
    0
      app/Models/PrimaNota.php
  73. 43
    0
      app/Models/RigaOrdine.php
  74. 10
    0
      app/Models/Saltacoda.php
  75. 12
    0
      app/Models/SaltacodaOrdine.php
  76. 10
    0
      app/Models/SaltacodaRigaordine.php
  77. 10
    0
      app/Models/Testi.php
  78. 2
    2
      app/Observers/OrdineObserver.php
  79. 45
    0
      app/Observers/PagamentoObserver.php
  80. 4
    1
      app/Providers/AppServiceProvider.php
  81. 1
    0
      composer.json
  82. 73
    1
      composer.lock
  83. 1
    1
      config/app.php
  84. 1
    3
      database/migrations/2026_03_23_221218_cucina.php
  85. 4
    4
      database/migrations/2026_03_23_221226_prenotazione.php
  86. 3
    6
      database/migrations/2026_03_23_221233_ordine.php
  87. 8
    8
      database/migrations/2026_03_23_222735_fornitore.php
  88. 3
    1
      database/migrations/2026_03_23_224652_dispositivo.php
  89. 1
    1
      database/migrations/2026_03_25_004526_bacheca.php
  90. 8
    0
      database/migrations/2026_03_25_004544_attivita.php
  91. 3
    0
      database/migrations/2026_03_25_212234_modifiche_alle_tabelle.php
  92. 4
    0
      database/migrations/2026_03_27_223801_metodo_pagamento.php
  93. 3
    0
      database/migrations/2026_03_27_223809_pagamento.php
  94. 32
    0
      database/migrations/2026_04_10_185625_testi.php
  95. 46
    0
      database/migrations/2026_04_10_222355_evento_form.php
  96. 36
    0
      database/migrations/2026_04_10_222649_prenotazione_form_risposta.php
  97. 37
    0
      database/migrations/2026_04_11_130945_opzione_form.php
  98. 29
    0
      database/migrations/2026_04_26_105216_modifica_riga_ordine.php
  99. 30
    0
      database/migrations/2026_04_26_112040_modifica_dispositivo_aggiungi_cucina.php
  100. 0
    0
      database/migrations/2026_04_26_115810_monitor_has_contenuto.php

+ 2
- 1
.env 查看文件

@@ -17,7 +17,8 @@ LOG_LEVEL=debug
17 17
 DB_CONNECTION=mysql
18 18
 DB_HOST=localhost
19 19
 DB_PORT=3306
20
-DB_DATABASE=segresta_fest
20
+DB_DATABASE=segresta_fest_2025_project
21
+#DB_DATABASE=segresta_fest
21 22
 DB_USERNAME=root
22 23
 DB_PASSWORD=
23 24
 

+ 6
- 2
app/DataTables/AttivitaDataTable.php 查看文件

@@ -32,6 +32,9 @@ class AttivitaDataTable extends DataTable
32 32
             ->addColumn('is_attiva_display', function($entity){
33 33
               return view('_partials.available', ['available' => $entity->is_attiva]);
34 34
             })
35
+            ->addColumn('seleziona_attivita' , function($entity){
36
+                return view('attivita._partials.parziali' , ['oggetto' => 'seleziona_attivita' ,'entity' => $entity]);
37
+            })
35 38
             ->setRowId('id');
36 39
     }
37 40
 
@@ -102,8 +105,9 @@ class AttivitaDataTable extends DataTable
102 105
             Column::make('nome'),
103 106
             Column::make('descrizione'),
104 107
             Column::make('path_logo'),
105
-            Column::make('path_icon'),
106
-            Column::make('path_image'),
108
+            Column::computed('seleziona_attivita'),
109
+            // Column::make('path_icon'),
110
+            // Column::make('path_image'),
107 111
             Column::computed('action')->title('')->width('10%')->addClass('text-center'),
108 112
         ];
109 113
     }

+ 116
- 0
app/DataTables/CategoriacontabileDataTable.php 查看文件

@@ -0,0 +1,116 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\Categoriacontabile;
6
+use Illuminate\Database\Eloquent\Builder as QueryBuilder;
7
+use Yajra\DataTables\EloquentDataTable;
8
+use Yajra\DataTables\Html\Builder as HtmlBuilder;
9
+use Yajra\DataTables\Html\Button;
10
+use Yajra\DataTables\Html\Column;
11
+use Yajra\DataTables\Html\Editor\Editor;
12
+use Yajra\DataTables\Html\Editor\Fields;
13
+use Yajra\DataTables\Services\DataTable;
14
+use Illuminate\Support\Facades\Auth;
15
+
16
+class CategoriacontabileDataTable extends DataTable
17
+{
18
+    public function __construct()
19
+    {
20
+        $this->dataTableVariable = 'dataTable_categoriacontabile';
21
+    }
22
+    /**
23
+     * Build the DataTable class.
24
+     *
25
+     * @param QueryBuilder<Categoriacontabile> $query Results from query() method.
26
+     */
27
+    public function dataTable(QueryBuilder $query): EloquentDataTable
28
+    {
29
+        return (new EloquentDataTable($query))
30
+            ->addColumn('action', function($entity){
31
+                return view('categoriacontabile.menu', ['entity' => $entity]);
32
+            })
33
+            ->addColumn('is_attiva_display', function($entity){
34
+                return view('_partials.available', ['available' => $entity->is_attiva]);
35
+            })
36
+            ->setRowId('id');
37
+    }
38
+
39
+    /**
40
+     * Get the query source of dataTable.
41
+     *
42
+     * @return QueryBuilder<Categoriacontabile>
43
+     */
44
+    public function query(Categoriacontabile $model): QueryBuilder
45
+    {
46
+        return $model->newQuery();
47
+    }
48
+
49
+    /**
50
+     * Optional method if you want to use the html builder.
51
+     */
52
+    public function html(): HtmlBuilder
53
+    {
54
+        $buttons = [];
55
+        if(Auth::user()->can('create-categoria_contabile')){
56
+            array_push($buttons, Button::make('create')
57
+                ->editor('editor')
58
+                ->className('btn btn-sm btn-primary mb-4')
59
+                ->formTitle('Crea nuova categoria contabile')
60
+                ->formButtons([
61
+                    Button::raw('Salva')
62
+                        ->className('btn btn-success ml-2 mx-2')
63
+                        ->actionHandler('create')
64
+                    ])
65
+                    ->text('<i class="fas fa-plus"></i> Nuova categoria contabile'));
66
+        }
67
+        
68
+        return $this->builder()
69
+                    ->setTableId($this->dataTableVariable)
70
+                    ->responsive(true)
71
+                    ->pageLength(25)
72
+                    ->lengthMenu([25, 50, 100])
73
+                    ->columns($this->getColumns())
74
+                    ->minifiedAjax()
75
+                    ->orderBy(1)
76
+                    ->selectStyleSingle()
77
+                    ->buttons($buttons)
78
+                    ->editor(
79
+                        Editor::make()
80
+                            ->fields([
81
+                                Fields\Text::make('nome')->label('Nome'),
82
+                                Fields\Text::make('descrizione')->label('Descrizione'),
83
+                                Fields\Boolean::make('is_attiva')->label('Attiva')->default(true),
84
+                            ])
85
+                    )
86
+                    ->initComplete("function(settings, json){
87
+                        initComplete_categoriacontabile();
88
+                    }");
89
+    }
90
+
91
+    /**
92
+     * Get the dataTable columns definition.
93
+     */
94
+    public function getColumns(): array
95
+    {
96
+        return [
97
+            Column::make('id'),
98
+            Column::make('nome')->title('Nome'),
99
+            Column::make('descrizione')->title('Descrizione'),
100
+            Column::make('is_attiva_display')->title('Attiva'),
101
+            Column::make('action')
102
+                  ->exportable(false)
103
+                  ->printable(false)
104
+                  ->width(60)
105
+                  ->addClass('text-center'),
106
+        ];
107
+    }
108
+
109
+    /**
110
+     * Get the filename for export.
111
+     */
112
+    protected function filename(): string
113
+    {
114
+        return 'Categoriacontabile_' . date('YmdHis');
115
+    }
116
+}

+ 93
- 0
app/DataTables/CategoriacontabileDataTableEditor.php 查看文件

@@ -0,0 +1,93 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\Categoriacontabile;
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 CategoriacontabileDataTableEditor extends DataTablesEditor
15
+{
16
+  protected $model = Categoriacontabile::class;
17
+  // protected $uploadDir = '';
18
+  // protected $disk = 'modelliRicevute';
19
+
20
+  protected $messages = [
21
+    'nome.required' => 'Il nome è richiesto',
22
+    'descrizione.required' => 'La descrizione è richiesta',
23
+    'is_attiva.required' => 'Indicare una delle due opzioni',
24
+  ];
25
+
26
+  /**
27
+  * Get create action validation rules.
28
+  *
29
+  * @return array
30
+  */
31
+  public function createRules(): array
32
+  {
33
+    return [
34
+      'nome'  => 'required|unique:categoria_contabile,nome',
35
+      'descrizione' => 'nullable',
36
+      'is_attiva' => 'boolean',
37
+    ];
38
+  }
39
+
40
+  public function createMessages(): array{
41
+    return $this->messages;
42
+  }
43
+
44
+  /**
45
+  * Get edit action validation rules.
46
+  *
47
+  * @param Model $model
48
+  * @return array
49
+  */
50
+  public function editRules(Model $model): array
51
+  {
52
+    return [
53
+      'nome'  => 'required|unique:categoria_contabile,nome,'.$model->id,
54
+      'descrizione' => 'nullable',
55
+      'is_attiva' => 'boolean',
56
+    ];
57
+  }
58
+
59
+  public function editMessages(): array{
60
+    return $this->messages;
61
+  }
62
+
63
+  /**
64
+  * Get remove action validation rules.
65
+  *
66
+  * @param Model $model
67
+  * @return array
68
+  */
69
+  public function removeRules(Model $model): array
70
+  {
71
+    return [];
72
+  }
73
+
74
+  public function creating(Model $model, array $data): array
75
+  {
76
+    // $model->roles()->sync([$data['ruolo_id']]);
77
+    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
78
+    return $data;
79
+  }
80
+
81
+  public function updating(Model $model, array $data): array
82
+  {
83
+    // dd($data['ruolo']);
84
+    // $model->roles()->sync([$data['ruolo_id']]);
85
+    $data['is_attiva'] = isset($data['is_attiva']) ? true : false;
86
+    return $data;
87
+  }
88
+  public function messages(): array
89
+  {
90
+    return $this->messages;
91
+  }
92
+
93
+}

+ 1
- 0
app/DataTables/ContenutoBachecaDataTable.php 查看文件

@@ -71,6 +71,7 @@ class ContenutoBachecaDataTable extends DataTable
71 71
                     ->language(asset('assets/Italian.json'))
72 72
                     ->dom(count($buttons) == 0 ? 'rtip' : 'Bfrtip')
73 73
                     ->buttons($buttons)
74
+                    ->ajax(route('contenuto-bacheca.index'))
74 75
                     ->initComplete("function(settings, json){
75 76
                         initComplete_contenuto_bacheca();
76 77
                     }")

+ 3
- 2
app/DataTables/ContenutoBachecaDataTableEditor.php 查看文件

@@ -8,7 +8,8 @@ use Illuminate\Validation\Rule;
8 8
 use Yajra\DataTables\DataTablesEditor;
9 9
 use Illuminate\Http\Request;
10 10
 use Illuminate\Validation\ValidationException;
11
-use Storage;
11
+use Illuminate\Http\JsonResponse;
12
+use Illuminate\Support\Facades\Storage;
12 13
 use Illuminate\Support\Str;
13 14
 
14 15
 class ContenutoBachecaDataTableEditor extends DataTablesEditor
@@ -91,7 +92,7 @@ class ContenutoBachecaDataTableEditor extends DataTablesEditor
91 92
     return $this->messages;
92 93
   }
93 94
 
94
-  public function updaload()
95
+  public function upload(Request $request): JsonResponse
95 96
   
96 97
   
97 98
   {

+ 1
- 1
app/DataTables/CucinaDataTable.php 查看文件

@@ -99,7 +99,7 @@ class CucinaDataTable extends DataTable
99 99
                             Fields\Image::make('immagine')->label('Immagine'),
100 100
                             Fields\Boolean::make('is_attiva')->label('Attiva')->default(true),  
101 101
                             Fields\Select2::make('attivita_id')->label('Attività')->options(Attivita::where('is_attiva', true)->pluck('id', 'nome')),
102
-                            Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::where('is_attiva', true)->pluck('id', 'nome')),
102
+                            // Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::where('is_attiva', true)->pluck('id', 'nome')),
103 103
                             Fields\Select2::make('stampante_id')->label('Stampante')->options(Dispositivo::where('tipo', Dispositivo::STAMPANTE)->pluck('id', 'nome')),
104 104
                         ])
105 105
                     )

+ 159
- 0
app/DataTables/EventoFormDataTable.php 查看文件

@@ -0,0 +1,159 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\EventoForm;
6
+use Illuminate\Database\Eloquent\Builder as QueryBuilder;
7
+use Yajra\DataTables\EloquentDataTable;
8
+use Yajra\DataTables\Html\Builder as HtmlBuilder;
9
+use Yajra\DataTables\Html\Button;
10
+use Yajra\DataTables\Html\Column;
11
+use Yajra\DataTables\Html\Editor\Editor;
12
+use Yajra\DataTables\Html\Editor\Fields;
13
+use Yajra\DataTables\Services\DataTable;
14
+use Illuminate\Support\Facades\Auth;
15
+
16
+class EventoFormDataTable extends DataTable
17
+{
18
+    public function __construct()
19
+    {
20
+        $this->dataTableVariable = 'dataTable_evento_form';
21
+    }
22
+    /**
23
+     * Build the DataTable class.
24
+     *
25
+     * @param QueryBuilder<EventoForm> $query Results from query() method.
26
+     */
27
+    public function dataTable(QueryBuilder $query): EloquentDataTable
28
+    {
29
+        return (new EloquentDataTable($query))
30
+            ->addColumn('action', function($entity){
31
+                return view('evento_form.menu', ['entity' => $entity]);
32
+            })
33
+            ->addColumn('tipo_display', function($entity){
34
+                return view('evento_form.tipi_campo', ['tipo' => $entity->tipo, 'id' => $entity->id]);
35
+            })
36
+            ->addColumn('obbligatoria', function($entity){
37
+                return view('_partials.available', ['available' => $entity->obbligatoria]);
38
+            })
39
+            ->addColumn('nascosta', function($entity){
40
+                return view('_partials.available', ['available' => $entity->nascosta]);
41
+            })
42
+            ->addColumn('nascondi_se_auth', function($entity){
43
+                return view('_partials.available', ['available' => $entity->nascondi_se_auth]);
44
+            })
45
+            ->addColumn('costo_display', function($entity){
46
+                return '€ ' . number_format($entity->costo, 2, ',', '.');
47
+            })
48
+            ->addColumn('posti_disponibili_display', function($entity){
49
+                return ($entity->posti_disponibili-15).'/'.$entity->posti_disponibili;
50
+            })
51
+            ->setRowId('id');
52
+    }
53
+
54
+    /**
55
+     * Get the query source of dataTable.
56
+     *
57
+     * @return QueryBuilder<EventoForm>
58
+     */
59
+    public function query(EventoForm $model): QueryBuilder
60
+    {
61
+        return $model->newQuery()->where('evento_id', $this->evento_id);
62
+    }
63
+
64
+    /**
65
+     * Optional method if you want to use the html builder.
66
+     */
67
+    public function html(): HtmlBuilder
68
+    {
69
+        $buttons = [];
70
+   
71
+        if(Auth::user()->can('create-evento_form')){
72
+            array_push($buttons, Button::make('create')
73
+                ->editor('editor')
74
+                ->className('btn btn-sm btn-success mb-4')
75
+                ->formTitle('Nuova richiesta')
76
+                ->formButtons([
77
+                    Button::raw('Annulla')
78
+                    ->className('btn btn-secondary ml-2')
79
+                    ->actionClose(),
80
+                    Button::raw('Salva')
81
+                    ->className('btn btn-success ml-2')
82
+                    ->actionHandler('create')
83
+                ])
84
+                ->text('<i class="fas fa-plus"></i> Nuova richiesta'));
85
+        }
86
+
87
+           
88
+        if(Auth::user()->can('create-evento_form')){
89
+            array_push($buttons, Button::raw('Aggiungi slot orario')
90
+                ->className('btn btn-sm btn-success mb-4')
91
+                ->action('aggiungiSlotOrario()')
92
+                ->text('<i class="fas fa-plus"></i> slot orario'));
93
+        }
94
+
95
+        return $this->builder()
96
+                    ->setTableId($this->dataTableVariable)
97
+                    ->columns($this->getColumns())
98
+                    ->language(asset('assets/Italian.json'))
99
+                    // ->ajax(route('evento-form.index', ['evento_id' => $this->evento_id]))
100
+                    ->buttons($buttons)
101
+                    ->minifiedAjax()
102
+                    ->ajax(route('form-evento.index', ['evento_id' => $this->evento_id]))
103
+                    ->editor(
104
+                        Editor::make()
105
+                            ->fields([
106
+                                Fields\Hidden::make('id'),
107
+                                Fields\Number::make('ordine_visualizzazione')->label('Ordine visualizzazione'),
108
+                                Fields\Text::make('label')->label('Label'),
109
+                                Fields\Text::make('descrizione')->label('Descrizione'),
110
+                                Fields\Boolean::make('obbligatoria')->label('Obbligatoria'),
111
+                                Fields\Boolean::make('nascosta')->label('Nascosta'),
112
+                                Fields\Select::make('tipo')->label('Tipo')->options(EventoForm::getTipi()->pluck('value', 'label')),
113
+                                Fields\Number::make('costo')->label('Costo'),
114
+                                Fields\Number::make('posti_disponibili')->label('Posti disponibili'),
115
+                                Fields\Boolean::make('nascondi_se_auth')->label('Nascondi se autenticato'),
116
+                                // Fields\Text::make('opzioni')->label('Opzioni'),
117
+                                // Fields\Number::make('remote_id')->label('Remote ID'),
118
+                                // Fields\Checkbox::make('posti_definiti_opzioni')->label('Posti definiti opzioni'),
119
+                            ])
120
+                    
121
+                    )
122
+                    // ->ajax(route('evento-form.store'))
123
+                    ->initComplete("function(settings, json){
124
+                        initComplete_evento_form();
125
+                    }")
126
+                    ->dom(count($buttons) == 0 ? 'rtip' : 'Bfrtip')
127
+                    ->responsive(true)
128
+                    ->orderBy(1)
129
+                    ->selectStyleSingle();
130
+                    }
131
+
132
+    /**
133
+     * Get the dataTable columns definition.
134
+     */
135
+    public function getColumns(): array
136
+    {
137
+        return [
138
+            Column::make('id')->visible(false),
139
+            Column::make('tipo_display')->addClass('text-center')->title('#'),
140
+            Column::make('label')->title('Richiesta'),
141
+            Column::make('costo_display')->addClass('text-center')->title('Costo'),
142
+            Column::make('obbligatoria')->addClass('text-center')->title('Obbligatoria'),
143
+            Column::make('nascosta')->addClass('text-center')->title('Nascosta'),
144
+            // Column::make('nascondi_se_auth')->addClass('text-center')->title('Nascondi se autenticato'),
145
+            Column::make('posti_disponibili_display')->addClass('text-center')->title('Posti disponibili'),
146
+            Column::computed('action')->addClass('text-center')->title('')
147
+                  ->width(60)
148
+                  ->addClass('text-center'),
149
+        ];
150
+    }
151
+
152
+    /**
153
+     * Get the filename for export.
154
+     */
155
+    protected function filename(): string
156
+    {
157
+        return 'EventoForm_' . date('YmdHis');
158
+    }
159
+}

+ 115
- 0
app/DataTables/EventoFormDataTableEditor.php 查看文件

@@ -0,0 +1,115 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\EventoForm;
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 EventoFormDataTableEditor extends DataTablesEditor
15
+{
16
+  protected $model = EventoForm::class;
17
+  // protected $uploadDir = '';
18
+  // protected $disk = 'modelliRicevute';
19
+
20
+  protected $messages = [
21
+    'label.required' => 'Il label è richiesto',
22
+    'descrizione.required' => 'La descrizione è richiesta',
23
+    'tipo.required' => 'Il tipo è richiesto',
24
+    'costo.required' => 'Il costo è richiesto',
25
+    'posti_disponibili.required' => 'Il numero di posti disponibili è richiesto',
26
+    'nascondi_se_auth.required' => 'Il nascondi se autenticato è richiesto',
27
+    'opzioni.required' => 'Le opzioni sono richieste',
28
+    'remote_id.required' => 'Il remote id è richiesto',
29
+    'posti_definiti_opzioni.required' => 'Il posti definiti opzioni è richiesto',
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
+      'descrizione' => 'nullable',
42
+      'tipo' => 'required',
43
+      'costo' => 'nullable|numeric|min:0',
44
+      'posti_disponibili' => 'nullable|numeric|min:0',
45
+      'nascondi_se_auth' => 'nullable|boolean',
46
+      'opzioni' => 'nullable',
47
+      'remote_id' => 'nullable|numeric|min:0',
48
+      'posti_definiti_opzioni' => 'nullable|boolean',
49
+      'ordine_visualizzazione' => 'nullable|numeric|min:0',
50
+    ];
51
+  }
52
+
53
+  public function createMessages(): array{
54
+    return $this->messages;
55
+  }
56
+
57
+  /**
58
+  * Get edit action validation rules.
59
+  *
60
+  * @param Model $model
61
+  * @return array
62
+  */
63
+  public function editRules(Model $model): array
64
+  {
65
+    return [
66
+      'label'  => 'required',
67
+      'descrizione' => 'nullable',
68
+      'tipo' => 'required',
69
+      'costo' => 'nullable|numeric|min:0',
70
+      'posti_disponibili' => 'nullable|numeric|min:0',
71
+      'nascondi_se_auth' => 'nullable|boolean',
72
+      'opzioni' => 'nullable',
73
+      'remote_id' => 'nullable|numeric|min:0',
74
+      'posti_definiti_opzioni' => 'nullable|boolean',
75
+      'ordine_visualizzazione' => 'nullable|numeric|min:0',
76
+    ];
77
+  }
78
+
79
+  public function editMessages(): array{
80
+    return $this->messages;
81
+  }
82
+
83
+  /**
84
+  * Get remove action validation rules.
85
+  *
86
+  * @param Model $model
87
+  * @return array
88
+  */
89
+  public function removeRules(Model $model): array
90
+  {
91
+    return [];
92
+  }
93
+
94
+  public function creating(Model $model, array $data): array
95
+  {
96
+    $eventoId = request()->query('evento_id') ?? request()->input('evento_id');
97
+    if ($eventoId) {
98
+      $data['evento_id'] = (int) $eventoId;
99
+    }
100
+
101
+    return $data;
102
+  }
103
+
104
+  public function updating(Model $model, array $data): array
105
+  {
106
+    // dd($data['ruolo']);
107
+    // $model->roles()->sync([$data['ruolo_id']]);
108
+    return $data;
109
+  }
110
+  public function messages(): array
111
+  {
112
+    return $this->messages;
113
+  }
114
+
115
+}

+ 2
- 1
app/DataTables/FornitoreDataTable.php 查看文件

@@ -41,7 +41,7 @@ class FornitoreDataTable extends DataTable
41 41
      */
42 42
     public function query(Fornitore $model): QueryBuilder
43 43
     {
44
-        return $model->newQuery()->where('attivita_id', session()->get('attivita_attuale'));
44
+        return $model->newQuery()->where('attivita_id', $this->attivita_id);
45 45
     }
46 46
 
47 47
     /**
@@ -70,6 +70,7 @@ class FornitoreDataTable extends DataTable
70 70
                     ->editor(
71 71
                         Editor::make()
72 72
                             ->fields([
73
+                                Fields\Hidden::make('attivita_id')->default($this->attivita_id),
73 74
                                 Fields\Text::make('nome')->label('Nome'),
74 75
                                 Fields\Text::make('email')->label('Email'),
75 76
                                 Fields\Text::make('telefono')->label('Telefono'),

+ 6
- 6
app/DataTables/FornitoreDataTableEditor.php 查看文件

@@ -38,12 +38,12 @@ class FornitoreDataTableEditor extends DataTablesEditor
38 38
     return [
39 39
       'nome'  => 'required',
40 40
       'email' => 'required|email',
41
-      'telefono' => 'required',
42
-      'indirizzo' => 'required',
43
-      'citta' => 'required',
44
-      'provincia' => 'required',
45
-      'cap' => 'required',
46
-      'paese' => 'required',
41
+      // 'telefono' => 'required',
42
+      // 'indirizzo' => 'required',
43
+      // 'citta' => 'required',
44
+      // 'provincia' => 'required',
45
+      // 'cap' => 'required',
46
+      // 'paese' => 'required',
47 47
     ];
48 48
   }
49 49
 

+ 11
- 6
app/DataTables/MonitorDataTable.php 查看文件

@@ -38,6 +38,10 @@ class MonitorDataTable extends DataTable
38 38
             ->addColumn('attivita_id_display', function($entity){
39 39
                 return $entity->attivita ? $entity->attivita->nome : 'ND';
40 40
             })
41
+            ->addColumn('contenuto_display', function($entity){
42
+                $monitor_has_contenuto = $entity->monitor_has_contenuto;
43
+                return $monitor_has_contenuto ? $monitor_has_contenuto->is_bacheca ? 'Bacheca: '.$monitor_has_contenuto->bacheca->nome : 'Cucina: '.$monitor_has_contenuto->cucina->nome : 'ND';
44
+            })
41 45
             ->setRowId('id');
42 46
     }
43 47
 
@@ -101,12 +105,13 @@ class MonitorDataTable extends DataTable
101 105
     {
102 106
         return [
103 107
             Column::make('id')->visible(false),
104
-            Column::make('is_attivo')->data('is_attivo_display')->title('Disponibile'),
105
-            Column::make('attivita_id')->title('Attività')->data('attivita_id_display'),
106
-            Column::make('nome'),
107
-            Column::make('licenza'),
108
-            Column::make('ubicazione'),
109
-            Column::make('note')->visible(false),
108
+            Column::make('is_attivo')->data('is_attivo_display')->title('Pubblicato'),
109
+            Column::make('attivita_id')->title('Attività')->data('attivita_id_display')->visible(false),
110
+            Column::make('nome')->title('Titolo'),
111
+            Column::make('licenza')->title('Licenza'),
112
+            Column::make('ubicazione')->title('Ubicazione'),
113
+            Column::make('contenuto_display')->title('Contenuto'),
114
+            Column::make('note')->title('Note')->visible(false),
110 115
             Column::computed('action')->title('')->width('10%')->addClass('text-center'),
111 116
         ];
112 117
     }

+ 118
- 0
app/DataTables/OpzioneFormDataTable.php 查看文件

@@ -0,0 +1,118 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\OpzioneForm;
6
+use Illuminate\Database\Eloquent\Builder as QueryBuilder;
7
+use Yajra\DataTables\EloquentDataTable;
8
+use Yajra\DataTables\Html\Builder as HtmlBuilder;
9
+use Yajra\DataTables\Html\Column;
10
+use Yajra\DataTables\Html\Button;
11
+use Yajra\DataTables\Services\DataTable;
12
+use Yajra\DataTables\Html\Editor\Editor;
13
+use Yajra\DataTables\Html\Editor\Fields;
14
+use Illuminate\Support\Facades\Auth;
15
+
16
+class OpzioneFormDataTable extends DataTable
17
+{
18
+    public function __construct()
19
+    {
20
+        $this->dataTableVariable = 'dataTable_opzione_form';
21
+    }
22
+
23
+    /**
24
+     * Build the DataTable class.
25
+     *
26
+     * @param QueryBuilder<OpzioneForm> $query Results from query() method.
27
+     */
28
+    public function dataTable(QueryBuilder $query): EloquentDataTable
29
+    {
30
+        return (new EloquentDataTable($query))
31
+            ->addColumn('action', function($entity){
32
+                return view('evento_form.opzioni.action', ['entity' => $entity]);
33
+            })
34
+            ->setRowId('id');
35
+    }
36
+
37
+    /**
38
+     * Get the query source of dataTable.
39
+     *
40
+     * @return QueryBuilder<OpzioneForm>
41
+     */
42
+    public function query(OpzioneForm $model): QueryBuilder
43
+    {
44
+        return $model->newQuery()->where('evento_form_id', $this->evento_form_id);
45
+    }
46
+
47
+    /**
48
+     * Optional method if you want to use the html builder.
49
+     */
50
+    public function html(): HtmlBuilder
51
+    {
52
+
53
+        $buttons = [];
54
+        if(Auth::user()->can('create-opzione_form')){
55
+            array_push($buttons, Button::make('create')
56
+                ->editor('editor')
57
+                ->className('btn btn-sm btn-success mb-4')
58
+                ->formTitle('Nuova opzione form')
59
+                ->formButtons([
60
+                    Button::raw('Annulla')
61
+                    ->className('btn btn-secondary ml-2')
62
+                    ->actionClose(),
63
+                    Button::raw('Salva')
64
+                    ->className('btn btn-success ml-2')
65
+                    ->actionHandler('create')
66
+                ])
67
+                ->text('<i class="fas fa-plus"></i> Nuova opzione form'));
68
+        }
69
+        return $this->builder()
70
+                    ->setTableId($this->dataTableVariable)
71
+                    ->columns($this->getColumns())
72
+                    ->minifiedAjax()
73
+                    ->ajax(route('opzione-form.index', ['evento_form_id' => $this->evento_form_id]))
74
+                    ->editor(
75
+                        Editor::make()
76
+                            ->fields([
77
+                                Fields\Hidden::make('id'),
78
+                                Fields\Hidden::make('evento_form_id')->default($this->evento_form_id),
79
+                                Fields\Text::make('label')->label('Label'),
80
+                                Fields\Number::make('costo')->label('Costo'),
81
+                                Fields\Number::make('posti_disponibili')->label('Posti disponibili'),
82
+                            ])
83
+                    )
84
+                    ->initComplete("function(settings, json){
85
+                        initComplete_opzione_form();
86
+                    }")
87
+                    ->responsive(true)
88
+                    ->orderBy(1)
89
+                    ->selectStyleSingle()
90
+                    ->language(asset('assets/Italian.json'))
91
+                    ->buttons($buttons)
92
+                    ->dom(count($buttons) === 0 ? 'rtip' : 'Bfrtip');
93
+    }
94
+
95
+    /**
96
+     * Get the dataTable columns definition.
97
+     */
98
+    public function getColumns(): array
99
+    {
100
+        return [
101
+            Column::make('id')->visible(false),
102
+            Column::make('label')->title('Nome'),
103
+            Column::make('costo')->title('Costo (€)'),
104
+            Column::make('posti_disponibili')->title('Posti disponibili (0 = illimitato)'),
105
+            Column::computed('action')->addClass('text-center')->title('')
106
+                  ->width(60)
107
+                  ->addClass('text-center'),
108
+        ];
109
+    }
110
+
111
+    /**
112
+     * Get the filename for export.
113
+     */
114
+    protected function filename(): string
115
+    {
116
+        return 'OpzioneForm_' . date('YmdHis');
117
+    }
118
+}

+ 50
- 0
app/DataTables/OpzioneFormDataTableEditor.php 查看文件

@@ -0,0 +1,50 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\OpzioneForm;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Yajra\DataTables\DataTablesEditor;
8
+
9
+class OpzioneFormDataTableEditor extends DataTablesEditor
10
+{
11
+    protected $model = OpzioneForm::class;
12
+
13
+    protected $messages = [
14
+        'label.required' => 'La label è obbligatoria',
15
+    ];
16
+
17
+    public function createRules(): array
18
+    {
19
+        return [
20
+            'label' => 'required',
21
+            'costo' => 'nullable|numeric|min:0',
22
+            'posti_disponibili' => 'nullable|integer|min:0',
23
+            'evento_form_id' => 'required|integer',
24
+        ];
25
+    }
26
+
27
+    public function editRules(Model $model): array
28
+    {
29
+        return [
30
+            'label' => 'required',
31
+            'costo' => 'nullable|numeric|min:0',
32
+            'posti_disponibili' => 'nullable|integer|min:0',
33
+        ];
34
+    }
35
+
36
+    public function removeRules(Model $model): array
37
+    {
38
+        return [];
39
+    }
40
+
41
+    public function creating(Model $model, array $data): array
42
+    {
43
+        $efId = request()->query('evento_form_id') ?? request()->input('evento_form_id');
44
+        if ($efId) {
45
+            $data['evento_form_id'] = (int) $efId;
46
+        }
47
+
48
+        return $data;
49
+    }
50
+}

+ 3
- 0
app/DataTables/OrdineDataTable.php 查看文件

@@ -104,6 +104,9 @@ class OrdineDataTable extends DataTable
104 104
                     ->setTableId($this->dataTableVariable)
105 105
                     ->columns($this->getColumns())
106 106
                     ->minifiedAjax()
107
+                    ->responsive(true)
108
+                    ->pageLength(25)
109
+                    ->lengthMenu([25, 50, 100])
107 110
                     ->orderBy(2, 'asc')
108 111
                     ->language(asset('assets/Italian.json'))
109 112
                     ->dom(count($buttons) == 0 ? 'rtip' : 'Bfrtip')

+ 20
- 5
app/DataTables/PiattoDataTable.php 查看文件

@@ -5,6 +5,7 @@ namespace App\DataTables;
5 5
 use App\Models\Piatto;
6 6
 use App\Models\Cucina;
7 7
 use App\Models\Menu;
8
+use App\Models\Attivita;
8 9
 use App\Models\Allergene;
9 10
 use Illuminate\Database\Eloquent\Builder as QueryBuilder;
10 11
 use Yajra\DataTables\EloquentDataTable;
@@ -66,7 +67,6 @@ class PiattoDataTable extends DataTable
66 67
      */
67 68
     public function query(Piatto $model): QueryBuilder
68 69
     {
69
-        if (isset($this->menu_id)) {
70 70
 
71 71
             if (isset($this->cucina_id)) {
72 72
                 return $model->newQuery()
@@ -77,7 +77,7 @@ class PiattoDataTable extends DataTable
77 77
             return $model->newQuery()
78 78
                 // ->where('menu_id', $this->menu_id)
79 79
                 ->with('cucina', 'elencoAllergeni');
80
-        }
80
+        
81 81
         return $model->newQuery()->where('attivita_id', session()->get('attivita_attuale'))->with('cucina', 'elencoAllergeni');
82 82
     }
83 83
 
@@ -94,10 +94,24 @@ class PiattoDataTable extends DataTable
94 94
                 ->className('btn btn-sm btn-primary mb-4')
95 95
                 ->text('<i class="fas fa-plus"></i> Nuovo piatto'));
96 96
         }
97
+
98
+        if (Auth::user()->can('view-cucina')) {
99
+
100
+            array_push($buttons, 
101
+            Button::raw()
102
+            ->formTitle('Visualizza tutte le cucine')
103
+            ->className('btn btn-sm btn-primary ml-2 mb-4')
104
+            ->action('GoToCucine()')
105
+            ->text('<i class="bx bx-chef-hat"></i> Tutte le cucine'));
106
+        }
107
+
108
+
97 109
         if (isset($this->cucina_id)) {
98
-            array_push($buttons, Button::raw('<button class="btn btn-sm btn-secondary ml-2 mb-4" onclick="GoToAllPiatti()">
99
-                <i class="bx bx-dish"></i> Tutti i piatti
100
-            </button>'));
110
+            array_push($buttons, Button::raw()
111
+            ->formTitle('Visualizza tutti i piatti')
112
+            ->className('btn btn-sm btn-primary ml-2 mb-4')
113
+            ->action('GoToAllPiatti()')
114
+            ->text('<i class="bx bx-dish"></i> Tutti i piatti'));
101 115
         }
102 116
         return $this->builder()
103 117
             ->setTableId($this->dataTableVariable)
@@ -115,6 +129,7 @@ class PiattoDataTable extends DataTable
115 129
             ->editor(
116 130
                 Editor::make()
117 131
                     ->fields([
132
+                        Fields\Select2::make('attivita_id')->label('Attività')->options(Attivita::where('is_attiva', true)->pluck('id', 'nome')),
118 133
                         Fields\Text::make('nome')->label('Nome'),
119 134
                         Fields\Text::make('descrizione')->label('Descrizione'),
120 135
                         Fields\Select2::make('cucina_id')->label('cucina')->options(Cucina::where('is_attiva', true)->pluck('id', 'nome')),

+ 13
- 4
app/DataTables/PrenotazioneDataTable.php 查看文件

@@ -34,13 +34,13 @@ class PrenotazioneDataTable extends DataTable
34 34
               return view('prenotazione.menu', ['entity' => $entity]);
35 35
             })
36 36
             ->addColumn('evento_id_display', function($entity){
37
-              return $entity->evento->nome;
37
+              return $entity->evento->nome??'';
38 38
             })
39 39
             ->addColumn('cucina_id_display', function($entity){
40
-              return $entity->cucina->nome;
40
+              return $entity->cucina->nome??'';
41 41
             })
42 42
             ->addColumn('stato_display', function($entity){
43
-              return view('prenotazione._partials.stato-prenotazione', ['stato' => $entity->stato]);
43
+              return view('prenotazione._partials.stato-prenotazione', ['stato' => $entity->stato??'']);
44 44
             })
45 45
             ->setRowId('id');
46 46
     }
@@ -91,6 +91,14 @@ class PrenotazioneDataTable extends DataTable
91 91
             );
92 92
         }
93 93
 
94
+        if(Auth::user()->can('report-prenotazione') || Auth::user()->can('segna-presenza-prenotazione')){
95
+            array_push($buttons, Button::raw('Report')
96
+                ->className('btn btn-sm btn-success mb-4')
97
+                ->action('reportPrenotazioni()')
98
+                ->text('<i class="fas fa-file-alt"></i> Report')
99
+            );
100
+        }
101
+
94 102
 
95 103
         //campi del form
96 104
 $fields = [
@@ -103,7 +111,7 @@ $fields = [
103 111
         ->options(Evento::where('is_attivo', true)->pluck('id', 'nome'))
104 112
         ->default(isset($this->evento_id) ? $this->evento_id : ''),
105 113
         Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::all()->pluck('id', 'nome')),
106
-        Fields\Select2::make('stato')->label('Stato')->options(Prenotazione::getStati()->pluck('value', 'label'))->default(Prenotazione::STATO_IN_ATTESA) ,
114
+        Fields\Select2::make('stato')->label('Stato')->options(Prenotazione::getStati()->pluck('value', 'label'))->default(Prenotazione::STATO_INVIATA) ,
107 115
         Fields\Text::make('note')->label('Note'),
108 116
         Fields\Text::make('codice')->label('Codice'),
109 117
         Fields\Text::make('stato_pagamento')->label('Stato pagamento'),
@@ -141,6 +149,7 @@ $fields = [
141 149
         return [
142 150
             Column::make('id')->title('ID')->width('10%')->visible(false),
143 151
             Column::make('stato')->data('stato_display')->title('Stato')->searchable(true)->filter(true),
152
+            Column::make('codice')->title('Codice'),
144 153
             Column::make('cognome')->title('Cognome'),
145 154
             Column::make('nome')->title('Nome'),
146 155
             Column::make('email')->title('Email'),

+ 138
- 22
app/DataTables/PrimaNotaDataTable.php 查看文件

@@ -3,6 +3,11 @@
3 3
 namespace App\DataTables;
4 4
 
5 5
 use App\Models\PrimaNota;
6
+use App\Models\Pagamento;
7
+use App\Models\Ordine;
8
+use App\Models\Prenotazione;
9
+use App\Models\Evento;
10
+use App\Models\Fornitore;
6 11
 use Illuminate\Database\Eloquent\Builder as QueryBuilder;
7 12
 use Yajra\DataTables\EloquentDataTable;
8 13
 use Yajra\DataTables\Html\Builder as HtmlBuilder;
@@ -12,6 +17,8 @@ use Yajra\DataTables\Html\Editor\Editor;
12 17
 use Yajra\DataTables\Html\Editor\Fields;
13 18
 use Yajra\DataTables\Services\DataTable;
14 19
 use Illuminate\Support\Facades\Auth;
20
+use Carbon\Carbon;
21
+
15 22
 
16 23
 class PrimaNotaDataTable extends DataTable
17 24
 {
@@ -28,7 +35,73 @@ class PrimaNotaDataTable extends DataTable
28 35
     {
29 36
         return (new EloquentDataTable($query))
30 37
             ->addColumn('action', function($entity){
31
-                return view('primanota.menu', ['entity' => $entity]);
38
+                return view('prima_nota.menu', ['entity' => $entity]);
39
+            })
40
+            ->addColumn('attivita_id_display', function($entity){
41
+                return $entity->attivita->nome??'N/A';
42
+            })
43
+            ->addColumn('pagamento_id_display', function($entity){
44
+                if(isset($entity->pagamento)){
45
+                    return view('prima_nota._partials.display', ['oggetto' => 'pagamento', 'entity' => $entity->pagamento]);
46
+                } else {
47
+                    return '-';
48
+                }
49
+            })
50
+            ->addColumn('ordine_id_display', function($entity){
51
+                if(isset($entity->ordine)){
52
+                    return view('prima_nota._partials.display', ['oggetto' => 'ordine', 'entity' => $entity->ordine]);
53
+                } else {
54
+                    return '-';
55
+                }
56
+            })
57
+            ->addColumn('prenotazione_id_display', function($entity){
58
+                if(isset($entity->prenotazione)){
59
+                    return view('prima_nota._partials.display', ['oggetto' => 'prenotazione', 'entity' => $entity->prenotazione]);
60
+                } else {
61
+                    return '-';
62
+                }            })
63
+            ->addColumn('evento_id_display', function($entity){
64
+                if(isset($entity->evento)){
65
+                    return view('prima_nota._partials.display', ['oggetto' => 'evento', 'entity' => $entity->evento]);
66
+                } else {
67
+                    return '-';
68
+                }
69
+            })
70
+            ->addColumn('fornitore_id_display', function($entity){
71
+                if(isset($entity->fornitore)){
72
+                    return view('prima_nota._partials.display', ['oggetto' => 'fornitore', 'entity' => $entity->fornitore]);
73
+                } else {
74
+                    return '-';
75
+                }
76
+            })
77
+            ->addColumn('importo_display', function($entity){
78
+                return '€ ' . number_format($entity->importo, 2, ',', '.');
79
+            })
80
+            ->addColumn('tipo_movimento_display', function($entity){
81
+                return PrimaNota::getTipiMovimento()->where('value', $entity->tipo_movimento)->first()['label']??'N/A';
82
+            })
83
+            ->addColumn('causale_display', function($entity){
84
+                return $entity->causale??'N/A';
85
+            })
86
+            ->addColumn('stato_display', function($entity){
87
+                // return PrimaNota::getStati()->where('value', $entity->stato)->first()['label']??'N/A';
88
+            })
89
+            ->addColumn('entrata_display', function($entity){
90
+                if($entity->tipo_movimento == PrimaNota::ENTRATA){  
91
+                    return view('prima_nota._partials.display', ['oggetto' => 'entrata', 'entity' => $entity]);
92
+                } else {
93
+                    return '-';
94
+                }
95
+            })
96
+            ->addColumn('uscita_display', function($entity){
97
+                if($entity->tipo_movimento == PrimaNota::USCITA){
98
+                    return view('prima_nota._partials.display', ['oggetto' => 'uscita', 'entity' => $entity]);
99
+                } else {
100
+                    return '-';
101
+                }
102
+            })
103
+            ->addColumn('data_display', function($entity){
104
+                return Carbon::parse($entity->created_at)->format('d/m/Y H:i');
32 105
             })
33 106
             ->setRowId('id');
34 107
     }
@@ -40,7 +113,7 @@ class PrimaNotaDataTable extends DataTable
40 113
      */
41 114
     public function query(PrimaNota $model): QueryBuilder
42 115
     {
43
-        return $model->newQuery();
116
+        return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('created_at', 'desc');
44 117
     }
45 118
 
46 119
     /**
@@ -53,9 +126,27 @@ class PrimaNotaDataTable extends DataTable
53 126
             array_push($buttons, Button::make('create')
54 127
                 ->editor('editor')
55 128
                 ->className('btn btn-sm btn-primary mb-4')
56
-                ->formTitle('Crea nuovo prima nota')
57
-                ->text('<i class="fas fa-plus"></i> Nuova prima nota'));
129
+                ->formTitle('Crea nuovo movimento')
130
+                ->formButtons([
131
+                    // Button::raw('Annulla')
132
+                    //     ->className('btn btn-secondary ml-2 mx-2')
133
+                    //     ->actionClose(),
134
+                    Button::raw('Salva')
135
+                        ->className('btn btn-success ml-2 mx-2')
136
+                        ->actionHandler('create')
137
+                ])
138
+                ->text('<i class="fas fa-plus"></i> Nuovo movimento'));
139
+        }
140
+
141
+        if(Auth::user()->can('edit-primanota')){
142
+            array_push($buttons, Button::raw('Report')
143
+                ->className('btn btn-sm btn-warning mb-4')
144
+                ->action('function(){
145
+                    reportPrimaNota();
146
+                }')
147
+                ->text('<i class="fas fa-file-alt"></i> Report'));
58 148
         }
149
+        
59 150
         return $this->builder()
60 151
                     ->setTableId($this->dataTableVariable)
61 152
                     ->columns($this->getColumns())
@@ -63,21 +154,41 @@ class PrimaNotaDataTable extends DataTable
63 154
                     ->language(asset('assets/Italian.json'))
64 155
                     ->dom(count($buttons) == 0 ? 'rtip' : 'Bfrtip')
65 156
                     ->buttons($buttons)
157
+                    ->responsive(true)
158
+                    ->pageLength(25)
159
+                    ->lengthMenu([25, 50, 100])
66 160
                     ->orderBy(1)    
67 161
                     ->selectStyleSingle()
68 162
                     ->buttons($buttons)
69 163
                     ->editor(
70 164
                         Editor::make()
71 165
                             ->fields([
72
-                                Fields\Text::make('nome')->label('Nome'),
73
-                                Fields\Text::make('descrizione')->label('Descrizione'),
74
-                                // Fields\Select2::make('stato')->label('Stato')->options(PrimNota::getStati()->pluck('value', 'label')),
166
+                                Fields\Hidden::make('attivita_id')->default($this->attivita_id),
75 167
                                 Fields\Select2::make('tipo_movimento')->label('Tipo movimento')->options(PrimaNota::getTipiMovimento()->pluck('value', 'label')),
168
+                                Fields\Text::make('importo')->label('Importo'),
76 169
                                 Fields\Text::make('causale')->label('Causale'),
77
-                                Fields\Text::make('note')->label('Note'),
78
-                                Fields\Text::make('stato_pagamento')->label('Stato pagamento'),
79
-                                Fields\Text::make('metodo_pagamento')->label('Metodo pagamento'),
80
-                                Fields\Text::make('info')->label('Info'),
170
+                                Fields\Text::make('riferimento')->label('Riferimento'),
171
+                                Fields\Select2::make('evento_id')
172
+                                ->label('Evento')
173
+                                ->options(
174
+                                    collect(['Nessun evento' => ''])->merge(Evento::all()->pluck('id', 'nome'))->toArray()
175
+                                ),
176
+                                Fields\Select2::make('fornitore_id')
177
+                                ->label('Fornitore')
178
+                                ->options(
179
+                                    collect(['Nessun fornitore' => ''])->merge(Fornitore::all()->pluck('id', 'nome'))->toArray()
180
+                                ),
181
+                                
182
+                                // Fields\Checkbox::make('tipo_movimento')->label('Tipo movimento')->options(PrimaNota::getTipiMovimento()->pluck('value', 'label')),
183
+                                // Fields\Select2::make('stato')->label('Stato')->options(PrimaNota::getStati()->pluck('value', 'label')),
184
+                                // Fields\Text::make('note')->label('Note'),
185
+                                // Fields\Select2::make('pagamento_id')->label('Pagamento')->options(Pagamento::all()->pluck('id', 'nome')),
186
+                                // Fields\Select2::make('ordine_id')->label('Ordine')->options(Ordine::all()->pluck('id', 'nome')),
187
+                                // Fields\Select2::make('prenotazione_id')->label('Prenotazione')->options(Prenotazione::all()->pluck('id', 'nome')),
188
+                                // Fields\Text::make('stato_pagamento')->label('Stato pagamento'),
189
+                                // Fields\Text::make('metodo_pagamento')->label('Metodo pagamento'),
190
+                                // Fields\Text::make('info')->label('Info'),
191
+      
81 192
                             ])
82 193
                     )
83 194
                     ->initComplete("function(settings, json){
@@ -92,17 +203,22 @@ class PrimaNotaDataTable extends DataTable
92 203
     {
93 204
         return [
94 205
             Column::make('id')->title('ID')->width('10%')->visible(false),
95
-            Column::make('attivita_id')->title('Attività')->data('attivita_id_display'),
96
-            Column::make('pagamento_id')->title('Pagamento')->data('pagamento_id_display'),
97
-            Column::make('ordine_id')->title('Ordine')->data('ordine_id_display'),
98
-            Column::make('prenotazione_id')->title('Prenotazione')->data('prenotazione_id_display'),
99
-            Column::make('evento_id')->title('Evento')->data('evento_id_display'),
100
-            Column::make('fornitore_id')->title('Fornitore')->data('fornitore_id_display'),
101
-            Column::make('riferimento')->title('Riferimento'),
102
-            Column::make('importo')->title('Importo'),
103
-            Column::make('tipo_movimento')->title('Tipo movimento'),
104
-            Column::make('causale')->title('Causale'),
105
-            Column::make('stato')->title('Stato'),
206
+            Column::make('attivita_id')->title('Attività')->data('attivita_id_display')->visible(false),
207
+            Column::computed('data_display')->title('Data'),
208
+            Column::make('causale')->title('Causale')->data('causale_display'),
209
+            Column::make('entrata')->title('Entrata')->data('entrata_display'),
210
+            Column::make('uscita')->title('Uscita')->data('uscita_display'),
211
+            // Column::make('pagamento_id')->title('Pagamento')->data('pagamento_id_display'),
212
+            // Column::make('ordine_id')->title('Ordine')->data('ordine_id_display'),
213
+            // Column::make('prenotazione_id')->title('Prenotazione')->data('prenotazione_id_display'),
214
+            // Column::make('evento_id')->title('Evento')->data('evento_id_display'),
215
+            // Column::make('fornitore_id')->title('Fornitore')->data('fornitore_id_display'),
216
+
217
+            
218
+            // Column::make('riferimento')->title('Riferimento'),
219
+            // Column::make('importo')->title('Importo')->data('importo_display'),
220
+            // Column::make('tipo_movimento')->title('Tipo movimento')->data('tipo_movimento_display'),
221
+            // Column::make('stato')->title('Stato'),
106 222
             Column::computed('action')
107 223
                   ->title('')
108 224
                   ->exportable(false)

+ 118
- 0
app/DataTables/PrimaNotaDataTableEditor.php 查看文件

@@ -0,0 +1,118 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\PrimaNota;
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 PrimaNotaDataTableEditor extends DataTablesEditor
15
+{
16
+  protected $model = PrimaNota::class;
17
+  // protected $uploadDir = '';
18
+  // protected $disk = 'modelliRicevute';
19
+
20
+  protected $messages = [
21
+    'riferimento.required' => 'Il riferimento è richiesto',
22
+    'cognome.required' => 'Il cognome è richiesto',
23
+    'importo.required' => 'L\'importo è richiesto',
24
+    'tipo_movimento.required' => 'Il tipo movimento è richiesto',
25
+    'causale.required' => 'La causale è richiesta',
26
+    'stato.required' => 'Il stato è richiesto',
27
+  ];
28
+
29
+  /**
30
+  * Get create action validation rules.
31
+  *
32
+  * @return array
33
+  */
34
+  public function createRules(): array
35
+  {
36
+    return [
37
+      'attivita_id' => 'required|exists:attivita,id',
38
+      'pagamento_id' => 'nullable|exists:pagamento,id',
39
+      'ordine_id' => 'nullable|exists:ordine,id',
40
+      'prenotazione_id' => 'nullable|exists:prenotazione,id',
41
+      'evento_id' => 'nullable|exists:evento,id',
42
+      'fornitore_id' => 'nullable|exists:fornitore,id',
43
+      'riferimento' => 'nullable|string',
44
+      'importo' => 'required|numeric',
45
+      'tipo_movimento' => 'required|string',   
46
+      'causale' => 'required|string',
47
+      // 'stato' => 'nullable|string',
48
+      // 'note' => 'nullable|string',
49
+      // 'codice' => 'nullable|string',
50
+      'stato_pagamento' => 'nullable|string',
51
+      'metodo_pagamento' => 'nullable|string',
52
+    ];
53
+  }
54
+
55
+  public function createMessages(): array{
56
+    return $this->messages;
57
+  }
58
+
59
+  /**
60
+  * Get edit action validation rules.
61
+  *
62
+  * @param Model $model
63
+  * @return array
64
+  */
65
+  public function editRules(Model $model): array
66
+  {
67
+    return [
68
+      'attivita_id' => 'required|exists:attivita,id',
69
+      'pagamento_id' => 'nullable|exists:pagamento,id',
70
+      'ordine_id' => 'nullable|exists:ordine,id',
71
+      'prenotazione_id' => 'nullable|exists:prenotazione,id',
72
+      'evento_id' => 'nullable|exists:evento,id',
73
+      'fornitore_id' => 'nullable|exists:fornitore,id',
74
+      'riferimento' => 'nullable|string',
75
+      'importo' => 'required|numeric',
76
+      'tipo_movimento' => 'required|string',   
77
+      'causale' => 'required|string',
78
+      'stato' => 'nullable|string',
79
+      // 'note' => 'nullable|string',
80
+      // 'codice' => 'nullable|string',
81
+      'stato_pagamento' => 'nullable|string',
82
+      'metodo_pagamento' => 'nullable|string',
83
+    ];
84
+  }
85
+
86
+  public function editMessages(): array{
87
+    return $this->messages;
88
+  }
89
+
90
+  /**
91
+  * Get remove action validation rules.
92
+  *
93
+  * @param Model $model
94
+  * @return array
95
+  */
96
+  public function removeRules(Model $model): array
97
+  {
98
+    return [];
99
+  }
100
+
101
+  public function creating(Model $model, array $data): array
102
+  {
103
+    // $model->roles()->sync([$data['ruolo_id']]);
104
+    return $data;
105
+  }
106
+
107
+  public function updating(Model $model, array $data): array
108
+  {
109
+    // dd($data['ruolo']);
110
+    // $model->roles()->sync([$data['ruolo_id']]);
111
+    return $data;
112
+  }
113
+  public function messages(): array
114
+  {
115
+    return $this->messages;
116
+  }
117
+
118
+}

+ 130
- 0
app/DataTables/PuntoOperatoreDataTable.php 查看文件

@@ -0,0 +1,130 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\Dispositivo;
6
+use App\Models\Attivita;
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 PuntoOperatoreDataTable extends DataTable
19
+{
20
+    public function __construct()
21
+    {
22
+        $this->dataTableVariable = 'dataTable_punto_operatore';
23
+    }
24
+    /**
25
+     * Build the DataTable class.
26
+     *
27
+     * @param QueryBuilder<Dispositivo> $query Results from query() method.
28
+     */
29
+    public function dataTable(QueryBuilder $query): EloquentDataTable
30
+    {
31
+        return (new EloquentDataTable($query))
32
+            ->addColumn('action', function($entity){
33
+                return view('punto_operatore.menu', ['entity' => $entity]);
34
+            })
35
+            ->addColumn('is_attivo_display', function($entity){
36
+                return view('_partials.available', ['available' => $entity->is_attivo]);
37
+            })
38
+            ->setRowId('id');
39
+    }
40
+
41
+    /**
42
+     * Get the query source of dataTable.
43
+     *
44
+     * @return QueryBuilder<PuntoOperatore>
45
+     */
46
+    public function query(Dispositivo $model): QueryBuilder
47
+    {
48
+        return $model->newQuery()
49
+        ->where('tipo', Dispositivo::OPERATORE)
50
+        ->where('attivita_id', $this->attivita_id);
51
+    }
52
+
53
+    /**
54
+     * Optional method if you want to use the html builder.
55
+     */
56
+    public function html(): HtmlBuilder
57
+    {
58
+        $buttons = [];
59
+        if(Auth::user()->can('create-punto_operatore')){
60
+            array_push($buttons, Button::make('create')
61
+                ->editor('editor')
62
+                ->className('btn btn-sm btn-primary mb-4')
63
+                ->formTitle('Crea nuovo punto di operatore')
64
+                ->text('<i class="fas fa-plus"></i> Nuovo punto di operatore'));
65
+        }
66
+
67
+        return $this->builder()
68
+                    ->setTableId($this->dataTableVariable)
69
+                    ->columns($this->getColumns())
70
+                    ->minifiedAjax()
71
+                    ->language(asset('assets/Italian.json'))
72
+                    ->dom(count($buttons) == 0 ? 'rtip' : 'Bfrtip')
73
+                    ->responsive(true)
74
+                    ->orderBy(1)
75
+                    ->selectStyleSingle()
76
+                    ->buttons($buttons)
77
+                    ->editor(
78
+                        Editor::make()
79
+                            ->fields([
80
+                                Fields\Text::make('nome')->label('Nome'),
81
+                                Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
82
+                                Fields\Hidden::make('tipo')->label('Tipo')->default(Dispositivo::OPERATORE),
83
+                                Fields\Text::make('licenza')->label('Licenza'),
84
+                                // Fields\Text::make('url_stampante')->label('URL della stampante'),
85
+                                Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::where('is_attiva', true)->pluck('id', 'nome')),
86
+                                Fields\Text::make('ubicazione')->label('Ubicazione'),
87
+                                Fields\Text::make('note')->label('Note'),
88
+                                Fields\Boolean::make('is_attivo')->label('Attivo')->default(true),
89
+                                // Fields\Text::make('pin_sblocco')->label('Pin di sblocco'),
90
+                                // Fields\DateTime::make('data_apertura_dispositivo')->label('Data di apertura del dispositivo'),
91
+                                // Fields\DateTime::make('data_chiusura_dispositivo')->label('Data di chiusura del dispositivo'),
92
+                                ])
93
+                    )
94
+                    ->initComplete("function(settings, json){
95
+                        initComplete_punto_operatore();
96
+                    }");
97
+    }
98
+
99
+    /**
100
+     * Get the dataTable columns definition.
101
+     */
102
+    public function getColumns(): array
103
+    {
104
+        return [
105
+            Column::make('id')->visible(false),
106
+            Column::make('is_attivo')->data('is_attivo_display')->title('Disponibile'),
107
+            Column::make('nome')->title('Nome'),
108
+            Column::make('attivita_id')->title('Attività'),
109
+            Column::make('tipo')->title('Tipo')->visible(true),
110
+            Column::make('licenza')->title('Licenza'),
111
+            Column::make('url_stampante')->title('URL della stampante'),
112
+            Column::make('ubicazione')->title('Ubicazione'),
113
+            Column::make('pin_sblocco')->title('Pin di sblocco'),
114
+            Column::computed('action')
115
+                  ->title('')
116
+                  ->exportable(false)
117
+                  ->printable(false)
118
+                  ->width(60)
119
+                  ->addClass('text-center'),
120
+        ];
121
+    }
122
+
123
+    /**
124
+     * Get the filename for export.
125
+     */
126
+    protected function filename(): string
127
+    {
128
+        return 'PuntoOperatore_' . date('YmdHis');
129
+    }
130
+}

+ 114
- 0
app/DataTables/PuntoOperatoreDataTableEditor.php 查看文件

@@ -0,0 +1,114 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\Dispositivo;
6
+use Illuminate\Database\Eloquent\Model;
7
+use Yajra\DataTables\DataTablesEditor;
8
+use Auth;
9
+
10
+class PuntoOperatoreDataTableEditor extends DataTablesEditor
11
+{
12
+  protected $model = Dispositivo::class;
13
+  // protected $uploadDir = '';
14
+  // protected $disk = 'modelliRicevute';
15
+
16
+  protected $messages = [
17
+    'nome.required' => 'Il nome è richiesto',
18
+    'attivita_id.required' => 'La attività è richiesta',
19
+    'tipo.required' => 'Il tipo è richiesto',
20
+    'licenza.required' => 'La licenza è richiesta',
21
+    'url_stampante.required' => 'L\'URL della stampante è richiesta',
22
+    'ubicazione.required' => 'L\'ubicazione è richiesta',
23
+    'note.required' => 'La note è richiesta',
24
+    'is_attivo.required' => 'Indicare una delle due opzioni',
25
+  ];
26
+
27
+  /**
28
+  * Get create action validation rules.
29
+  *
30
+  * @return array
31
+  */
32
+  public function createRules(): array
33
+  {
34
+    return [
35
+      'nome'  => 'required',
36
+      'attivita_id' => 'required|exists:attivita,id',
37
+      'tipo' => 'required',
38
+      'licenza' => 'nullable',
39
+      'url_stampante' => 'nullable',
40
+      'ubicazione' => 'nullable',
41
+      'note' => 'nullable',
42
+      'is_attivo' => 'boolean',
43
+      'pin_sblocco' => 'nullable',
44
+      'data_apertura_dispositivo' => 'nullable|date',
45
+      'data_chiusura_dispositivo' => 'nullable|date',
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
+      'nome'  => 'required',
63
+      'attivita_id' => 'required|exists:attivita,id',
64
+      'tipo' => 'required',
65
+      'licenza' => 'nullable',
66
+      'url_stampante' => 'nullable',
67
+      'ubicazione' => 'nullable',
68
+      'note' => 'nullable',
69
+      'is_attivo' => 'boolean',
70
+      'pin_sblocco' => 'nullable',
71
+      'data_apertura_dispositivo' => 'nullable|date',
72
+      'data_chiusura_dispositivo' => 'nullable|date',
73
+    ];
74
+  }
75
+
76
+  public function editMessages(): array{
77
+    return $this->messages;
78
+  }
79
+
80
+  /**
81
+  * Get remove action validation rules.
82
+  *
83
+  * @param Model $model
84
+  * @return array
85
+  */
86
+  public function removeRules(Model $model): array
87
+  {
88
+    return [];
89
+  }
90
+
91
+  public function creating(Model $model, array $data): array
92
+  {
93
+    // L'Editor manda `allergeni` come array di ID selezionati:
94
+    // salviamo la relazione nella pivot `piatto_allergene`, non nella colonna `piatto.allergeni`.
95
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
96
+    return $data;
97
+  }
98
+
99
+  public function updating(Model $model, array $data): array
100
+  {
101
+    $data['is_attivo'] = isset($data['is_attivo']) ? true : false;
102
+    return $data;
103
+  }
104
+
105
+  public function saved(Model $model, array $data): Model
106
+  {
107
+    return $model;
108
+  }
109
+  public function messages(): array
110
+  {
111
+    return $this->messages;
112
+  }
113
+
114
+}

+ 109
- 0
app/DataTables/TestiDataTable.php 查看文件

@@ -0,0 +1,109 @@
1
+<?php
2
+
3
+namespace App\DataTables;
4
+
5
+use App\Models\Testi;
6
+use App\Models\Attivita;
7
+use Illuminate\Database\Eloquent\Builder as QueryBuilder;
8
+use Yajra\DataTables\EloquentDataTable;
9
+use Yajra\DataTables\Html\Builder as HtmlBuilder;
10
+use Yajra\DataTables\Html\Button;
11
+use Yajra\DataTables\Html\Column;
12
+use Yajra\DataTables\Html\Editor\Editor;
13
+use Yajra\DataTables\Html\Editor\Fields;
14
+use Yajra\DataTables\Services\DataTable;
15
+use Illuminate\Support\Facades\Auth;
16
+
17
+class TestiDataTable extends DataTable
18
+{
19
+    public function __construct(){
20
+        $this->dataTableVariable = 'dataTable_testi';
21
+    }
22
+    /**
23
+     * Build the DataTable class.
24
+     *
25
+     * @param QueryBuilder<Testi> $query Results from query() method.
26
+     */
27
+    public function dataTable(QueryBuilder $query): EloquentDataTable
28
+    {
29
+        return (new EloquentDataTable($query))
30
+            ->addColumn('action', function($entity){
31
+                return view('testi.menu', ['entity' => $entity]);
32
+            })
33
+            ->setRowId('id');
34
+    }
35
+
36
+    /**
37
+     * Get the query source of dataTable.
38
+     *
39
+     * @return QueryBuilder<Testi>
40
+     */
41
+    public function query(Testi $model): QueryBuilder
42
+    {
43
+        return $model->newQuery()->where('attivita_id', session()->get('attivita_attuale'));
44
+    }
45
+
46
+    /**
47
+     * Optional method if you want to use the html builder.
48
+     */
49
+    public function html(): HtmlBuilder
50
+    {
51
+        $buttons = [];
52
+        if(Auth::user()->can('create-testi')){
53
+            array_push($buttons, Button::make('create')
54
+                ->editor('editor')
55
+                ->formTitle('Crea nuovo testo')
56
+                ->className('btn btn-sm btn-primary mb-4')
57
+                ->text('<i class="fas fa-plus"></i> Nuovo testo'));
58
+        }
59
+
60
+        return $this->builder()
61
+                    ->setTableId($this->dataTableVariable)
62
+                    ->columns($this->getColumns())
63
+                    ->minifiedAjax()
64
+                    ->buttons($buttons)
65
+                    ->responsive(true)
66
+                    ->orderBy(1)
67
+                    ->selectStyleSingle()
68
+                    ->language(asset('assets/Italian.json'))
69
+                    ->dom(count($buttons) == 0 ? 'rtip' : 'Bfrtip')
70
+                    ->buttons($buttons)
71
+                    ->editor(
72
+                        Editor::make()
73
+                            ->fields([
74
+                                Fields\Select2::make('attivita_id')->label('Attività')->options(Attivita::all()->pluck('id', 'nome')),
75
+                                Fields\Text::make('titolo')->label('Titolo'),
76
+                                Fields\Text::make('descrizione')->label('Descrizione'),
77
+                                Fields\Boolean::make('is_attivo')->label('Attivo')->default(true),
78
+                                // Fields\Select::make('ambiente')->label('Ambiente')->options(),
79
+                                // Fields\Select::make('tipo')->label('Tipo')->options(Testi::getTipi()->pluck('value', 'label')),
80
+                                Fields\TextArea::make('testo')->label('Testo'),
81
+                            ])
82
+                    )
83
+                    ->initComplete("function(settings, json){
84
+                        initComplete_testi();
85
+                    }");
86
+    }
87
+
88
+    /**
89
+     * Get the dataTable columns definition.
90
+     */
91
+    public function getColumns(): array
92
+    {
93
+        return [
94
+            Column::make('id')->title('ID')->width('10%')->visible(false),
95
+            Column::make('titolo')->title('Titolo'),
96
+            Column::make('descrizione')->title('Descrizione'),
97
+            // Column::make('testo')->title('Testo'),
98
+            Column::computed('action')->title('')->width('10%')->addClass('text-center'),
99
+        ];
100
+    }
101
+
102
+    /**
103
+     * Get the filename for export.
104
+     */
105
+    protected function filename(): string
106
+    {
107
+        return 'Testi_' . date('YmdHis');
108
+    }
109
+}

+ 104
- 0
app/DataTables/TestiDataTableEditor.php 查看文件

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

+ 331
- 1
app/Http/Controllers/BilancioController.php 查看文件

@@ -2,7 +2,13 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+use App\Models\Attivita;
6
+use App\Models\PrimaNota;
7
+use App\Models\Pagamento;
8
+use App\Models\RigaOrdine;
5 9
 use Illuminate\Http\Request;
10
+use Carbon\Carbon;
11
+use Carbon\CarbonPeriod;
6 12
 
7 13
 class BilancioController extends Controller
8 14
 {
@@ -26,6 +32,330 @@ class BilancioController extends Controller
26 32
 
27 33
     public function oggi(Request $request)
28 34
     {
29
-        return view('bilancio.oggi');
35
+        $attivitaId = session()->get('attivita_attuale');
36
+        $dayStart = now()->startOfDay();
37
+        $dayEnd = now()->endOfDay();
38
+
39
+        $attivita = Attivita::find($attivitaId);
40
+
41
+        $righeOrdiniOggi = RigaOrdine::query()
42
+            ->with(['piatto.cucina', 'ordine'])
43
+            ->whereHas('ordine', function ($query) use ($attivitaId, $dayStart, $dayEnd) {
44
+                $query
45
+                    ->where('attivita_id', $attivitaId)
46
+                    ->whereBetween('created_at', [$dayStart, $dayEnd]);
47
+            })
48
+            ->get();
49
+
50
+        $righeIncassiOggi = RigaOrdine::query()
51
+            ->with(['piatto.cucina', 'ordine'])
52
+            ->whereHas('ordine.pagamenti', function ($query) use ($attivitaId, $dayStart, $dayEnd) {
53
+                $query
54
+                    ->where('attivita_id', $attivitaId)
55
+                    ->whereBetween('created_at', [$dayStart, $dayEnd]);
56
+            })
57
+            ->get();
58
+
59
+        $righeOggi = $righeOrdiniOggi
60
+            ->concat($righeIncassiOggi)
61
+            ->unique('id')
62
+            ->values();
63
+
64
+        $cucineRows = $righeOggi
65
+            ->groupBy(function ($riga) {
66
+                return $riga->piatto?->cucina_id ?: 0;
67
+            })
68
+            ->map(function ($items, $cucinaId) {
69
+                $first = $items->first();
70
+                $cucinaNome = $first?->piatto?->cucina?->nome ?? ('Cucina #' . $cucinaId);
71
+
72
+                $piatti = $items
73
+                    ->groupBy('piatto_id')
74
+                    ->map(function ($piattoItems) {
75
+                        $firstPiatto = $piattoItems->first();
76
+                        $quantita = (int) $piattoItems->sum(function ($r) {
77
+                            return (int) ($r->quantita ?? 0);
78
+                        });
79
+                        $totale = (float) $piattoItems->sum(function ($r) {
80
+                            return ((float) ($r->quantita ?? 0)) * ((float) ($r->prezzo ?? 0));
81
+                        });
82
+
83
+                        return [
84
+                            'nome' => $firstPiatto?->piatto?->nome ?? 'Piatto',
85
+                            'quantita' => $quantita,
86
+                            'totale' => $totale,
87
+                        ];
88
+                    })
89
+                    ->sortByDesc('quantita')
90
+                    ->values();
91
+
92
+                $totQuantita = (int) $piatti->sum('quantita');
93
+                $totImporto = (float) $piatti->sum('totale');
94
+
95
+                return [
96
+                    'id' => $cucinaId,
97
+                    'nome' => $cucinaNome,
98
+                    'piatti' => $piatti,
99
+                    'tot_quantita' => $totQuantita,
100
+                    'tot_importo' => $totImporto,
101
+                ];
102
+            })
103
+            ->sortByDesc('tot_quantita')
104
+            ->values();
105
+
106
+        $pagamentiOggi = Pagamento::query()
107
+            ->with(['metodo_pagamento', 'ordine.righe_ordine.piatto.cucina'])
108
+            ->where('attivita_id', $attivitaId)
109
+            ->whereBetween('created_at', [$dayStart, $dayEnd])
110
+            ->get();
111
+
112
+        $paymentSummary = $pagamentiOggi
113
+            ->groupBy(function ($pagamento) {
114
+                return $pagamento->metodo_pagamento?->nome
115
+                    ?? $pagamento->metodo_pagamento?->tipo
116
+                    ?? 'N/D';
117
+            })
118
+            ->map(function ($items, $metodo) {
119
+                return [
120
+                    'metodo' => (string) $metodo,
121
+                    'count' => $items->count(),
122
+                    'totale' => (float) $items->sum(function ($p) {
123
+                        return (float) ($p->importo ?? 0);
124
+                    }),
125
+                ];
126
+            })
127
+            ->sortByDesc('totale')
128
+            ->values();
129
+
130
+        $totaleIncassoOggi = (float) $pagamentiOggi->sum(function ($p) {
131
+            return (float) ($p->importo ?? 0);
132
+        });
133
+
134
+        $hourLabels = collect(range(0, 23))->map(function ($h) {
135
+            return str_pad((string) $h, 2, '0', STR_PAD_LEFT);
136
+        })->values();
137
+
138
+        $heatmapSeries = $cucineRows->map(function ($cucinaRow) use ($pagamentiOggi) {
139
+            $cucinaNome = (string) ($cucinaRow['nome'] ?? 'Cucina');
140
+            $cucinaId = (int) ($cucinaRow['id'] ?? 0);
141
+            $data = [];
142
+            foreach (range(0, 23) as $h) {
143
+                $hourTotal = (int) $pagamentiOggi
144
+                    ->filter(function ($pagamento) use ($h) {
145
+                        return !empty($pagamento->created_at) && (int) $pagamento->created_at->format('H') === $h;
146
+                    })
147
+                    ->sum(function ($pagamento) use ($cucinaId) {
148
+                        if (empty($pagamento->ordine)) {
149
+                            return 0;
150
+                        }
151
+                        return (int) $pagamento->ordine->righe_ordine->sum(function ($riga) use ($cucinaId) {
152
+                            $rigaCucinaId = (int) ($riga->piatto?->cucina_id ?? 0);
153
+                            if ($rigaCucinaId !== $cucinaId) {
154
+                                return 0;
155
+                            }
156
+                            return (int) ($riga->quantita ?? 0);
157
+                        });
158
+                    });
159
+                $data[] = $hourTotal;
160
+            }
161
+            return [
162
+                'name' => $cucinaNome,
163
+                'data' => $data,
164
+            ];
165
+        })->values();
166
+
167
+        return view('bilancio.oggi', [
168
+            'attivita' => $attivita,
169
+            'oggiLabel' => now()->format('d/m/Y'),
170
+            'cucineRows' => $cucineRows,
171
+            'paymentSummary' => $paymentSummary,
172
+            'totaleIncassoOggi' => $totaleIncassoOggi,
173
+            'heatmapHourLabels' => $hourLabels,
174
+            'heatmapSeries' => $heatmapSeries,
175
+        ]);
176
+    }
177
+
178
+    public function index(Request $request)
179
+    {
180
+        $attivitaId = session()->get('attivita_attuale');
181
+        $attivita = Attivita::find($attivitaId);
182
+
183
+        $year = (int) $request->get('anno', now()->year);
184
+        if ($year < 2000 || $year > 2100) {
185
+            $year = (int) now()->year;
186
+        }
187
+
188
+        $yearStart = Carbon::create($year, 1, 1)->startOfDay();
189
+        $yearEnd = Carbon::create($year, 12, 31)->endOfDay();
190
+
191
+        $movimentiCollection = PrimaNota::query()
192
+            ->with(['fornitore', 'pagamento.metodo_pagamento'])
193
+            ->when($attivitaId, function ($query) use ($attivitaId) {
194
+                $query->where('attivita_id', $attivitaId);
195
+            })
196
+            ->whereBetween('created_at', [$yearStart, $yearEnd])
197
+            ->orderBy('created_at')
198
+            ->get();
199
+
200
+        $movimenti = $movimentiCollection->map(function ($movimento) {
201
+            $tipoRaw = strtolower((string) ($movimento->tipo_movimento ?? ''));
202
+            $isUscita = $tipoRaw === 'uscita' || ((float) ($movimento->importo ?? 0)) < 0;
203
+
204
+            return [
205
+                'data' => $movimento->created_at,
206
+                'tipo' => $isUscita ? 'uscita' : 'entrata',
207
+                'importo' => abs((float) ($movimento->importo ?? 0)),
208
+                'pagamento_id' => (int) ($movimento->pagamento_id ?? 0),
209
+                'fornitore_id' => (int) ($movimento->fornitore_id ?? 0),
210
+                'fornitore_nome' => $movimento->fornitore?->nome,
211
+                'causale' => trim((string) ($movimento->causale ?? '')),
212
+                'riferimento' => trim((string) ($movimento->riferimento ?? '')),
213
+                'metodo' => $movimento->pagamento?->metodo_pagamento?->nome
214
+                    ?? $movimento->pagamento?->metodo_pagamento?->tipo
215
+                    ?? null,
216
+            ];
217
+        })->values();
218
+
219
+        $ricaviTotali = (float) $movimenti->where('tipo', 'entrata')->sum('importo');
220
+        $costiTotali = (float) $movimenti->where('tipo', 'uscita')->sum('importo');
221
+
222
+        // Fallback per ricavi se la prima nota non contiene entrate.
223
+        $pagamentiCollection = Pagamento::query()
224
+            ->with('metodo_pagamento')
225
+            ->when($attivitaId, function ($query) use ($attivitaId) {
226
+                $query->where('attivita_id', $attivitaId);
227
+            })
228
+            ->whereBetween('created_at', [$yearStart, $yearEnd])
229
+            ->orderBy('created_at')
230
+            ->get();
231
+
232
+        if ($ricaviTotali <= 0 && $pagamentiCollection->isNotEmpty()) {
233
+            $ricaviTotali = (float) $pagamentiCollection->sum(function ($pagamento) {
234
+                return (float) ($pagamento->importo ?? 0);
235
+            });
236
+        }
237
+
238
+        $saldo = $ricaviTotali - $costiTotali;
239
+
240
+        $mesiBase = collect(CarbonPeriod::create($yearStart->copy(), '1 month', $yearEnd->copy()))
241
+            ->map(function (Carbon $date) {
242
+                return [
243
+                    'month_key' => $date->format('Y-m'),
244
+                    'mese' => $date->translatedFormat('M'),
245
+                    'ricavi' => 0.0,
246
+                    'costi' => 0.0,
247
+                    'saldo' => 0.0,
248
+                ];
249
+            })
250
+            ->keyBy('month_key');
251
+
252
+        foreach ($movimenti as $movimento) {
253
+            if (!$movimento['data']) {
254
+                continue;
255
+            }
256
+            $monthKey = Carbon::parse($movimento['data'])->format('Y-m');
257
+            if (!$mesiBase->has($monthKey)) {
258
+                continue;
259
+            }
260
+            $row = $mesiBase->get($monthKey);
261
+            if ($movimento['tipo'] === 'entrata') {
262
+                $row['ricavi'] += $movimento['importo'];
263
+            } else {
264
+                $row['costi'] += $movimento['importo'];
265
+            }
266
+            $row['saldo'] = $row['ricavi'] - $row['costi'];
267
+            $mesiBase->put($monthKey, $row);
268
+        }
269
+
270
+        $andamentoMensile = $mesiBase->values();
271
+
272
+        $costiRows = $movimenti
273
+            ->where('tipo', 'uscita')
274
+            ->groupBy(function ($movimento) {
275
+                $fornitore = trim((string) ($movimento['fornitore_nome'] ?? ''));
276
+                if ($fornitore !== '') {
277
+                    return 'Fornitore: ' . $fornitore;
278
+                }
279
+                $causale = trim((string) ($movimento['causale'] ?? ''));
280
+                if ($causale !== '') {
281
+                    return $causale;
282
+                }
283
+                $riferimento = trim((string) ($movimento['riferimento'] ?? ''));
284
+                if ($riferimento !== '') {
285
+                    return $riferimento;
286
+                }
287
+                return 'Uscita varia';
288
+            })
289
+            ->map(function ($items, $voce) {
290
+                return [
291
+                    'voce' => (string) $voce,
292
+                    'movimenti' => $items->count(),
293
+                    'totale' => (float) $items->sum('importo'),
294
+                ];
295
+            })
296
+            ->sortByDesc('totale')
297
+            ->values();
298
+
299
+        $ricaviBase = $movimenti->where('tipo', 'entrata');
300
+        $ricaviRows = $ricaviBase
301
+            ->groupBy(function ($movimento) {
302
+                if ((int) ($movimento['pagamento_id'] ?? 0) > 0) {
303
+                    $metodo = trim((string) ($movimento['metodo'] ?? ''));
304
+                    return $metodo !== '' ? ('Pagamento: ' . $metodo) : 'Pagamento: N/D';
305
+                }
306
+                $causale = trim((string) ($movimento['causale'] ?? ''));
307
+                if ($causale !== '') {
308
+                    return $causale;
309
+                }
310
+                $riferimento = trim((string) ($movimento['riferimento'] ?? ''));
311
+                if ($riferimento !== '') {
312
+                    return $riferimento;
313
+                }
314
+                return 'Entrata varia';
315
+            })
316
+            ->map(function ($items, $voce) {
317
+                return [
318
+                    'voce' => (string) $voce,
319
+                    'movimenti' => $items->count(),
320
+                    'totale' => (float) $items->sum('importo'),
321
+                ];
322
+            })
323
+            ->sortByDesc('totale')
324
+            ->values();
325
+
326
+        // Fallback: se Prima Nota non contiene entrate, usa i pagamenti dell'anno.
327
+        if ($ricaviRows->isEmpty() && $pagamentiCollection->isNotEmpty()) {
328
+            $ricaviRows = $pagamentiCollection
329
+                ->groupBy(function ($pagamento) {
330
+                    $metodo = $pagamento->metodo_pagamento?->nome
331
+                        ?? $pagamento->metodo_pagamento?->tipo
332
+                        ?? 'N/D';
333
+                    return 'Pagamento: ' . $metodo;
334
+                })
335
+                ->map(function ($items, $voce) {
336
+                    return [
337
+                        'voce' => (string) $voce,
338
+                        'movimenti' => $items->count(),
339
+                        'totale' => (float) $items->sum(function ($pagamento) {
340
+                            return (float) ($pagamento->importo ?? 0);
341
+                        }),
342
+                    ];
343
+                })
344
+                ->sortByDesc('totale')
345
+                ->values();
346
+        }
347
+
348
+        return view('bilancio.index', [
349
+            'attivita' => $attivita,
350
+            'selectedYear' => $year,
351
+            'anniSelezionabili' => collect(range((int) now()->year, (int) now()->year - 5)),
352
+            'ricaviTotali' => $ricaviTotali,
353
+            'costiTotali' => $costiTotali,
354
+            'saldoTotale' => $saldo,
355
+            'movimentiCount' => $movimenti->count(),
356
+            'andamentoMensile' => $andamentoMensile,
357
+            'costiRows' => $costiRows,
358
+            'ricaviRows' => $ricaviRows,
359
+        ]);
30 360
     }
31 361
 }

+ 24
- 6
app/Http/Controllers/CarrelloController.php 查看文件

@@ -37,22 +37,39 @@ class CarrelloController extends Controller
37 37
 
38 38
     public function aumenta(Request $request){
39 39
         $request->validate([
40
-            'ordine_id' => 'required|integer|exists:ordine,id',
40
+            'ordine_id' => 'nullable|integer',
41 41
             'piatto_id' => 'required|integer|exists:piatto,id',
42 42
             'dispositivo_id' => 'required|integer|exists:dispositivo,id',
43 43
             'attivita_id' => 'nullable|integer|exists:attivita,id',
44 44
         ]);
45 45
 
46
-        /** Stesso ordine mostrato in cassa: non usare updateOrCreate con session (crea disallineamenti). */
47
-        $carrello = Ordine::query()
48
-            ->whereKey($request->ordine_id)
46
+        // Tolleranza su ordine_id stale: se non e` valido, usa/crea il carrello corrente per dispositivo+attivita.
47
+        $carrelloBaseQuery = Ordine::query()
49 48
             ->where('stato', Ordine::CARRELLO)
50 49
             ->where('dispositivo_id', $request->dispositivo_id)
51 50
             ->when(
52 51
                 $request->filled('attivita_id'),
53 52
                 fn ($q) => $q->where('attivita_id', $request->attivita_id)
54
-            )
55
-            ->firstOrFail();
53
+            );
54
+
55
+        $carrello = null;
56
+        if ($request->filled('ordine_id')) {
57
+            $carrello = (clone $carrelloBaseQuery)
58
+                ->whereKey($request->ordine_id)
59
+                ->first();
60
+        }
61
+
62
+        if (!$carrello) {
63
+            $carrello = (clone $carrelloBaseQuery)->latest('id')->first();
64
+        }
65
+
66
+        if (!$carrello) {
67
+            $carrello = Ordine::create([
68
+                'stato' => Ordine::CARRELLO,
69
+                'dispositivo_id' => $request->dispositivo_id,
70
+                'attivita_id' => $request->attivita_id,
71
+            ]);
72
+        }
56 73
 
57 74
         $riga = RigaOrdine::where('ordine_id', $carrello->id)->where('piatto_id', $request->piatto_id)->first();
58 75
         if($riga){
@@ -71,6 +88,7 @@ class CarrelloController extends Controller
71 88
         return response()->json([
72 89
             'success' => true,
73 90
             'message' => 'Quantità aumentata',
91
+            'ordine_id' => $carrello->id,
74 92
             'data' => $riga,
75 93
         ]);
76 94
     }

+ 53
- 0
app/Http/Controllers/CategoriaContabileController.php 查看文件

@@ -0,0 +1,53 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use Illuminate\Http\Request;
6
+use App\Models\Categoriacontabile;
7
+use App\DataTables\CategoriacontabileDataTable;
8
+use App\DataTables\CategoriacontabileDataTableEditor;
9
+use Illuminate\Support\Facades\Auth;
10
+
11
+class CategoriaContabileController extends Controller
12
+{
13
+    public static $permission_group = "Categoria Contabile";
14
+    public static $permissions = [
15
+        'view-categoria_contabile' => 'Vedi',
16
+        'create-categoria_contabile' => 'Crea',
17
+        'edit-categoria_contabile' => 'Modifica',
18
+        'delete-categoria_contabile' => 'Elimina',
19
+    ];
20
+    
21
+    public static function middleware(): array
22
+    {
23
+        return [
24
+            new Middleware('permission:view-categoria_contabile', only: ['index']),
25
+            new Middleware('permission:create-categoria_contabile|edit-categoria_contabile|delete-categoria_contabile', only: ['store', 'update', 'destroy']),
26
+        ];
27
+    }
28
+    
29
+    public function index(CategoriacontabileDataTable $dataTable)
30
+    {
31
+        return $dataTable->render('categoria_contabile.index');
32
+    }
33
+    
34
+    public function store(CategoriacontabileDataTableEditor $editor)
35
+    {
36
+        $request = request();
37
+        $input = $request->all();
38
+        if($request->has('action')){
39
+            switch($input['action']){
40
+                case 'create':
41
+                    if(!Auth::user()->can('create-categoria_contabile')) return;
42
+                    break;
43
+                case 'edit':
44
+                    if(!Auth::user()->can('edit-categoria_contabile')) return;
45
+                    break;
46
+                case 'delete':
47
+                    if(!Auth::user()->can('delete-categoria_contabile')) return;
48
+                    break;
49
+            }
50
+        }
51
+        return $editor->process($request);
52
+    }
53
+}

+ 41
- 1
app/Http/Controllers/ConsultaController.php 查看文件

@@ -2,8 +2,12 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
-use Illuminate\Http\Request;
6 5
 use App\Models\Ordine;
6
+use App\Models\Prenotazione;
7
+use Endroid\QrCode\Builder\Builder;
8
+use Endroid\QrCode\Color\Color;
9
+use Endroid\QrCode\Writer\SvgWriter;
10
+use Illuminate\Http\Request;
7 11
 
8 12
 class ConsultaController extends Controller
9 13
 {
@@ -30,4 +34,40 @@ class ConsultaController extends Controller
30 34
         }
31 35
         return view('consulta.comanda.show', compact('ordine'));
32 36
     }
37
+    public function prenotazione_show(Request $request)
38
+    {
39
+        $prenotazione = Prenotazione::query()
40
+            ->with([
41
+                'risposte',
42
+                'evento.form' => function ($q) {
43
+                    $q->orderBy('ordine_visualizzazione')->with('opzioni_form');
44
+                },
45
+            ])
46
+            ->where('codice', $request->get('codice'))
47
+            ->first();
48
+        if (!$prenotazione) {
49
+            return redirect()->route('consulta.index')->with('error', 'Prenotazione non trovata');
50
+        }
51
+
52
+        $qrBuilder = new Builder(
53
+            writer: new SvgWriter(),
54
+            writerOptions: [
55
+                SvgWriter::WRITER_OPTION_EXCLUDE_XML_DECLARATION => true,
56
+            ],
57
+        );
58
+
59
+        $codiceQrSvg = $qrBuilder->build(
60
+            data: (string) $prenotazione->codice,
61
+            size: 168,
62
+            margin: 4,
63
+            foregroundColor: new Color(21, 38, 92),
64
+            // class: 'bg-primary',
65
+            // backgroundColor: new Color(245, 130, 32),
66
+        )->getString();
67
+
68
+        return view('consulta.prenotazione.show', [
69
+            'prenotazione' => $prenotazione,
70
+            'codiceQrSvg' => $codiceQrSvg,
71
+        ]);
72
+    }
33 73
 }

+ 8
- 0
app/Http/Controllers/EndpointController.php 查看文件

@@ -93,6 +93,14 @@ class EndpointController extends Controller
93 93
             }
94 94
             $forMapping = [];
95 95
             foreach($endpoint->info['stampanti'] as $stampante_id){
96
+                if(!Dispositivo::find($stampante_id)){
97
+                 Log::error('Stampante non trovata: ' . $stampante_id);
98
+                    return response()->json([
99
+                        'message' => 'Stampante non trovata',
100
+                        'status' => 'error',
101
+                        'success' => false,
102
+                    ]);
103
+                }
96 104
                 // dd([$stampante_id , Dispositivo::find($stampante_id)]);
97 105
                 $forMapping[] = [
98 106
                     'id' => $stampante_id,

+ 10
- 0
app/Http/Controllers/EventoController.php 查看文件

@@ -7,6 +7,8 @@ use App\Models\Evento;
7 7
 use App\DataTables\EventoDataTable;
8 8
 use App\DataTables\EventoDataTableEditor;
9 9
 use Illuminate\Support\Facades\Auth;
10
+use App\DataTables\EventoFormDataTable;
11
+
10 12
 
11 13
 class EventoController extends Controller
12 14
 {
@@ -83,4 +85,12 @@ class EventoController extends Controller
83 85
       $evento->save();
84 86
       return redirect()->route('evento.gallery.edit', ['evento_id' => $evento->id])->with('success', 'Foto aggiunta con successo');
85 87
     }
88
+
89
+    public function edit(Request $request , EventoFormDataTable $dataTable)
90
+    {
91
+      $evento = Evento::find($request->get('evento_id'));
92
+      $dataTable->evento_id = $evento->id;
93
+      return $dataTable->render('evento.edit', compact('evento'));
94
+    }
95
+
86 96
 }

+ 59
- 0
app/Http/Controllers/EventoFormController.php 查看文件

@@ -0,0 +1,59 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use Illuminate\Http\Request;
6
+use App\Models\EventoForm;
7
+use App\Models\Evento;
8
+use App\DataTables\EventoFormDataTable;
9
+use App\DataTables\EventoFormDataTableEditor;
10
+use Illuminate\Support\Facades\Auth;
11
+
12
+class EventoFormController extends Controller
13
+{
14
+    public static $permission_group = "Form-Eventi";
15
+    public static $permissions = [
16
+        'view-evento_form' => 'Vedi',
17
+        'create-evento_form' => 'Crea',
18
+        'edit-evento_form' => 'Modifica',
19
+        'delete-evento_form' => 'Elimina',
20
+    ];
21
+
22
+    public static function middleware(): array
23
+    {
24
+        return [
25
+            new Middleware('permission:view-evento_form', only: ['index']), 
26
+            new Middleware('permission:create-evento_form|edit-evento_form|delete-evento_form', only: ['store', 'update', 'destroy']),
27
+        ];
28
+    }
29
+
30
+
31
+
32
+    public function index(Request $request, EventoFormDataTable $dataTable)
33
+    {
34
+        $dataTable->evento_id = $request->get('evento_id');
35
+        return $dataTable->render('evento_form.index');
36
+    }
37
+
38
+    public function store(EventoFormDataTableEditor $editor)
39
+    {
40
+        $request = request();
41
+        $input = $request->all();
42
+        if($request->has('action')){
43
+            switch($input['action']){
44
+                case 'create':
45
+                    if(!Auth::user()->can('create-evento_form')) return;
46
+                    break;
47
+                case 'edit':
48
+                    if(!Auth::user()->can('edit-evento_form')) return;
49
+                    break;
50
+                case 'delete':
51
+                    if(!Auth::user()->can('delete-evento_form')) return;
52
+                    break;
53
+            }
54
+        }
55
+        return $editor->process($request);
56
+    }
57
+
58
+
59
+}

+ 18
- 1
app/Http/Controllers/FornitoreController.php 查看文件

@@ -21,13 +21,14 @@ class FornitoreController extends Controller
21 21
     public static function middleware(): array
22 22
     {
23 23
         return [
24
-            new Middleware('permission:view-fornitore', only: ['index']),
24
+            new Middleware('permission:view-fornitore', only: ['index', 'show']),
25 25
             new Middleware('permission:create-fornitore|edit-fornitore|delete-fornitore', only: ['store', 'update', 'destroy']),
26 26
         ];
27 27
     }
28 28
     
29 29
     public function index(FornitoreDataTable $dataTable)
30 30
     {
31
+        $dataTable->attivita_id = session()->get('attivita_attuale');
31 32
         return $dataTable->render('fornitore.index');
32 33
     }
33 34
     
@@ -50,4 +51,20 @@ class FornitoreController extends Controller
50 51
         }
51 52
         return $editor->process($request);
52 53
     }
54
+
55
+    public function show_modal(Request $request)
56
+    {
57
+        $fornitore = Fornitore::find($request->get('fornitore_id'));
58
+        if(!$fornitore) return redirect()->route('fornitore.index')->with('error', 'Fornitore non trovato');
59
+        if(!Auth::user()->can('view-fornitore')) return abort(403, 'Non hai permesso di vedere questo fornitore');
60
+        return view('fornitore.show_modal', ['fornitore' => $fornitore]);
61
+    }
62
+
63
+    public function show(Request $request)
64
+    {
65
+        $fornitore = Fornitore::find($request->get('fornitore_id'));
66
+        if(!$fornitore) return redirect()->route('fornitore.index')->with('error', 'Fornitore non trovato');
67
+        if(!Auth::user()->can('view-fornitore')) return abort(403, 'Non hai permesso di vedere questo fornitore');
68
+        return view('fornitore.show', ['fornitore' => $fornitore]);
69
+    }
53 70
 }

+ 127
- 3
app/Http/Controllers/MonitorController.php 查看文件

@@ -4,9 +4,13 @@ namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6 6
 use App\Models\Dispositivo;
7
+use App\Models\MonitorHasContenuto;
8
+use App\Models\Bacheca;
7 9
 use App\DataTables\MonitorDataTable;
8 10
 use App\DataTables\MonitorDataTableEditor;
9 11
 use Illuminate\Support\Facades\Auth;
12
+use Carbon\Carbon;
13
+
10 14
 
11 15
 class MonitorController extends Controller
12 16
 {
@@ -49,9 +53,129 @@ class MonitorController extends Controller
49 53
         }
50 54
         return $editor->process($request);
51 55
     }
52
-    public function show($monitor_id)
56
+    public function show(Request $request)
57
+    {
58
+        $monitor = Dispositivo::find($request->get('monitor_id'));
59
+        if($monitor == null){
60
+            return redirect()->route('monitor.index')->with('error', 'Dispositivo monitor non trovato');
61
+        }
62
+
63
+        $monitor_has_contenuto = MonitorHasContenuto::with(['cucina', 'contenuto_bacheca', 'bacheca.contenuti'])
64
+            ->where('monitor_id', $monitor->id)
65
+            ->first();
66
+
67
+        // Fallback legacy: configurazioni vecchie legate al singolo contenuto.
68
+        if(
69
+            $monitor_has_contenuto != null &&
70
+            $monitor_has_contenuto->is_bacheca &&
71
+            empty($monitor_has_contenuto->bacheca_id) &&
72
+            !empty($monitor_has_contenuto->contenuto_bacheca_id)
73
+        ){
74
+            $legacyBacheca = Bacheca::with('contenuti')
75
+                ->where('attivita_id', $monitor->attivita_id)
76
+                ->whereHas('contenuti', function ($query) use ($monitor_has_contenuto) {
77
+                    $query->where('contenuto_bacheca.id', $monitor_has_contenuto->contenuto_bacheca_id);
78
+                })
79
+                ->first();
80
+
81
+            if ($legacyBacheca) {
82
+                $monitor_has_contenuto->setRelation('bacheca', $legacyBacheca);
83
+            }
84
+        }
85
+
86
+        if($monitor_has_contenuto != null){
87
+            if($monitor_has_contenuto->is_bacheca){
88
+                return view('monitor.show.bacheca', ['monitor' => $monitor, 'monitor_has_contenuto' => $monitor_has_contenuto]);
89
+            } else {
90
+                return view('monitor.show.chiamata_cucina', ['monitor' => $monitor, 'monitor_has_contenuto' => $monitor_has_contenuto]);
91
+            }
92
+        }
93
+
94
+        // return redirect()->route('monitor.index')->with('error', 'Contenuto monitor non trovato');
95
+    }
96
+
97
+    public function gestisci_contenuto_monitor(Request $request)
98
+    {
99
+        $monitor = Dispositivo::find($request->get('monitor_id'));
100
+        if($monitor == null){
101
+            abort(404, 'Dispositivo monitor non trovato');
102
+        }
103
+        $monitor_has_contenuto = MonitorHasContenuto::where('monitor_id', $monitor->id)->first();
104
+
105
+        $bacheche = Bacheca::query()
106
+            ->where('attivita_id', $monitor->attivita_id)
107
+            ->where('is_attiva', true)
108
+            ->whereHas('contenuti')
109
+            ->orderBy('nome')
110
+            ->get();
111
+
112
+        $bacheca_id = $monitor_has_contenuto?->bacheca_id;
113
+
114
+        // Fallback legacy: se era salvato un singolo contenuto, provo a risalire alla bacheca.
115
+        if (!$bacheca_id && !empty($monitor_has_contenuto?->contenuto_bacheca_id)) {
116
+            $legacyBacheca = Bacheca::query()
117
+                ->where('attivita_id', $monitor->attivita_id)
118
+                ->whereHas('contenuti', function ($query) use ($monitor_has_contenuto) {
119
+                    $query->where('contenuto_bacheca.id', $monitor_has_contenuto->contenuto_bacheca_id);
120
+                })
121
+                ->first();
122
+
123
+            $bacheca_id = $legacyBacheca?->id;
124
+        }
125
+
126
+        return view('monitor._partials.gestisci_contenuto', [
127
+            'monitor' => $monitor,
128
+            'monitor_has_contenuto' => $monitor_has_contenuto,
129
+            'is_bacheca' => $monitor_has_contenuto?->is_bacheca,
130
+            'cucina_id' => $monitor_has_contenuto?->cucina_id,
131
+            'bacheca_id' => $bacheca_id,
132
+            'bacheche' => $bacheche,
133
+        ]);
134
+    }
135
+
136
+    public function gestisci_contenuto_store(Request $request)
137
+    {
138
+        $request->validate([
139
+            'monitor_id' => 'required|exists:dispositivo,id',
140
+            'is_bacheca' => 'required|boolean',
141
+            'cucina_id' => 'nullable|required_if:is_bacheca,0|exists:cucina,id',
142
+            'bacheca_id' => 'nullable|required_if:is_bacheca,1|exists:bacheca,id',
143
+        ]);
144
+
145
+        $isBacheca = (bool) $request->boolean('is_bacheca');
146
+
147
+        MonitorHasContenuto::updateOrCreate([
148
+            'monitor_id' => $request->get('monitor_id'),
149
+        ], [
150
+            'is_bacheca' => $isBacheca,
151
+            'cucina_id' => $isBacheca ? null : $request->get('cucina_id'),
152
+            'bacheca_id' => $isBacheca ? $request->get('bacheca_id') : null,
153
+            'contenuto_bacheca_id' => null,
154
+        ]);
155
+
156
+        return response()->json(['success' => true, 'message' => 'Contenuto monitor aggiornato con successo']);
157
+    }
158
+
159
+
160
+    public function checkReload(Request $request)
53 161
     {
54
-        $monitor = Monitor::find($monitor_id);
55
-        return view('monitor.show', ['monitor' => $monitor]);
162
+        $monitor = Dispositivo::find($request->get('monitor_id'));
163
+        if($monitor == null){
164
+            abort(404, 'Dispositivo monitor non trovato');
165
+        }
166
+        $monitor_has_contenuto = MonitorHasContenuto::where('monitor_id', $monitor->id)->first();
167
+        if($monitor_has_contenuto == null){
168
+            abort(404, 'Contenuto monitor non trovato');
169
+        }
170
+
171
+        $last_updated_at = Carbon::parse($request->get('last_updated_at'));
172
+        if($last_updated_at == null){
173
+            return response()->json(['success' => false, 'reload' => false, 'message' => 'Data di aggiornamento non valida']);
174
+        }
175
+        if(!$monitor_has_contenuto->updated_at->eq($last_updated_at)){
176
+   
177
+            return response()->json(['success' => true, 'reload' => true, 'message' => 'Contenuto monitor aggiornato', 'last_updated_at' => $monitor_has_contenuto->updated_at->format('Y-m-d H:i:s')]);
178
+        }
179
+        return response()->json(['success' => false, 'reload' => false, 'message' => 'Contenuto monitor non aggiornato', 'last_updated_at' => $monitor_has_contenuto->updated_at->format('Y-m-d H:i:s')]);
56 180
     }
57 181
 }

+ 57
- 0
app/Http/Controllers/OpzioneFormController.php 查看文件

@@ -0,0 +1,57 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use Illuminate\Http\Request;
6
+use Illuminate\Routing\Controllers\Middleware;
7
+use App\Models\OpzioneForm;
8
+use App\DataTables\OpzioneFormDataTable;
9
+use App\DataTables\OpzioneFormDataTableEditor;
10
+use Illuminate\Support\Facades\Auth;
11
+
12
+class OpzioneFormController extends Controller
13
+{
14
+    public static $permission_group = "Opzione Form";
15
+    public static $permissions = [
16
+        'view-opzione_form' => 'Vedi',
17
+        'create-opzione_form' => 'Crea',
18
+        'edit-opzione_form' => 'Modifica',
19
+        'delete-opzione_form' => 'Elimina',
20
+    ];
21
+
22
+    public static function middleware(): array
23
+    {
24
+        return [
25
+            new Middleware('permission:view-opzione_form', only: ['index']),
26
+            new Middleware('permission:create-opzione_form|edit-opzione_form|delete-opzione_form', only: ['store', 'update', 'destroy']),
27
+        ];
28
+    }
29
+
30
+    public function index(Request $request, OpzioneFormDataTable $dataTable)
31
+    {
32
+        $dataTable->evento_form_id = $request->get('evento_form_id');
33
+        return $dataTable->render('evento_form.opzioni.index');
34
+    }
35
+
36
+    public function store(OpzioneFormDataTableEditor $editor)
37
+    {
38
+        $request = request();
39
+        $input = $request->all();
40
+        if($request->has('action')){
41
+            switch($input['action']){
42
+                case 'create':
43
+                    if(!Auth::user()->can('create-opzione_form')) return;
44
+                    break;
45
+                case 'edit':
46
+                    if(!Auth::user()->can('edit-opzione_form')) return;
47
+                    break;
48
+                case 'delete':
49
+                    if(!Auth::user()->can('delete-opzione_form')) return;
50
+                    break;
51
+            }
52
+        }
53
+        return $editor->process($request);
54
+    }
55
+
56
+   
57
+}

+ 6
- 0
app/Http/Controllers/OrdineController.php 查看文件

@@ -56,5 +56,11 @@ class OrdineController extends Controller
56 56
         $ordine = Ordine::find($request->get('ordine_id'));
57 57
         return view('ordine.show', compact('ordine'));
58 58
     }
59
+
60
+    public function show_modal(Request $request)
61
+    {
62
+        $ordine = Ordine::find($request->get('ordine_id'));
63
+        return view('ordine.show_modal', compact('ordine'));
64
+    }
59 65
 }
60 66
 

+ 6
- 5
app/Http/Controllers/PagamentoController.php 查看文件

@@ -22,7 +22,7 @@ class PagamentoController extends Controller
22 22
     public static function middleware(): array
23 23
     {
24 24
         return [
25
-            new Middleware('permission:view-pagamento', only: ['index']),
25
+            new Middleware('permission:view-pagamento', only: ['index', 'show']),
26 26
             new Middleware('permission:create-pagamento|edit-pagamento|delete-pagamento', only: ['store', 'update', 'destroy']),
27 27
         ];
28 28
     }
@@ -55,9 +55,10 @@ class PagamentoController extends Controller
55 55
     public function show(Request $request)
56 56
     {
57 57
         $pagamento = Pagamento::find($request->get('pagamento_id'));
58
-        return view('pagamento.show', compact('pagamento'));
59
-    }
60
-
58
+        if(!$pagamento) return redirect()->route('pagamento.index')->with('error', 'Pagamento non trovato');
61 59
 
62
-    
60
+        if(!Auth::user()->can('view-pagamento')) return abort(403, 'Non hai permesso di vedere questo pagamento');
61
+        // if($request->has('modal')){
62
+        return view('pagamento.show', ['pagamento' => $pagamento]);
63
+    }
63 64
 }

+ 72
- 0
app/Http/Controllers/PrenotazioneController.php 查看文件

@@ -4,10 +4,13 @@ namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6 6
 use App\Models\Prenotazione;
7
+use App\Models\PrenotazioneRisposta;
7 8
 use App\DataTables\PrenotazioneDataTable;
8 9
 use App\DataTables\PrenotazioneDataTableEditor;
9 10
 use Illuminate\Support\Facades\Auth;
10 11
 use App\Models\Evento;
12
+use Illuminate\Support\Facades\Validator;
13
+use Illuminate\Support\Str;
11 14
 
12 15
 
13 16
 class PrenotazioneController extends Controller
@@ -18,6 +21,7 @@ class PrenotazioneController extends Controller
18 21
         'create-prenotazione' => 'Crea',
19 22
         'edit-prenotazione' => 'Modifica',
20 23
         'delete-prenotazione' => 'Elimina',
24
+        'report-prenotazione' => 'Report',
21 25
     ];
22 26
 
23 27
     public static function middleware(): array
@@ -65,4 +69,72 @@ class PrenotazioneController extends Controller
65 69
         return view('prenotazione._partials.modal', ['prenotazione' => $prenotazione]);
66 70
     }
67 71
 
72
+    public function prenota_form(Request $request){
73
+        $evento = Evento::find($request->evento_id);
74
+        if(!$evento){
75
+            return response()->json(['success' => false , 'messagge' => 'Evento non trovato']);
76
+        }
77
+        return view('prenotazione.cliente.prenota')->with(['evento' => $evento]);
78
+    }
79
+
80
+    public function prenota(Request $request){
81
+
82
+$evento = Evento::find($request->evento_id);
83
+
84
+// dd($request->all());
85
+
86
+$validator = Validator::make($request->all(), [
87
+    'nome' => 'required',
88
+    'cognome' => 'required',
89
+    'email' => 'required|email',
90
+    'telefono' => 'required',
91
+    'evento_id' => 'nullable|exists:evento,id',
92
+    'cucina_id' => 'nullable|exists:cucina,id',
93
+    'note' => 'nullable',
94
+    'codice' => 'nullable|unique:prenotazione,codice',
95
+    'stato_pagamento' => 'nullable',
96
+    'metodo_pagamento' => 'nullable',
97
+    'stato' => 'nullable|string',
98
+]);
99
+
100
+if($validator->fails()){
101
+    return response()->json(['success' => false , 'messagge' => $validator->errors()->first()]);
102
+}
103
+
104
+
105
+$prenotazione = new Prenotazione();
106
+$prenotazione->fill($request->all());
107
+$prenotazione->stato = Prenotazione::STATO_INVIATA;
108
+$prenotazione->codice = strtoupper(Str::random(5));
109
+$prenotazione->save();
110
+
111
+// Recupera tutti i campi che iniziano con 'prenotazione_risposta_'
112
+foreach ($request->all() as $key => $value) {
113
+    if (strpos($key, 'prenotazione_risposta_') === 0) {
114
+        $formId = str_replace('prenotazione_risposta_', '', $key);
115
+
116
+        PrenotazioneRisposta::create([
117
+            'prenotazione_id' => $prenotazione->id,
118
+            'evento_form_id' => $formId,
119
+            'risposta' => $value,
120
+        ]);
121
+    }
122
+}
123
+
124
+// dd($prenotazione->risposte);
125
+if(!$evento){
126
+    return response()->json(['success' => false , 'messagge' => 'Evento non trovato']);
127
+}
128
+        return view('consulta.prenotazione.show')->with(['prenotazione' => $prenotazione]);
129
+        // return response()->json(['success' => true , 'message' => 'prenota']);
130
+    }
131
+
132
+
133
+
134
+
135
+    public function report_index(Request $request)
136
+    {
137
+        return view('prenotazione.report.index');
138
+    }
139
+
68 140
 }

+ 10
- 0
app/Http/Controllers/PrenotazioneRisposteController.php 查看文件

@@ -0,0 +1,10 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use Illuminate\Http\Request;
6
+
7
+class PrenotazioneRisposteController extends Controller
8
+{
9
+    //
10
+}

+ 1
- 0
app/Http/Controllers/PrimaNotaController.php 查看文件

@@ -28,6 +28,7 @@ class PrimaNotaController extends Controller
28 28
 
29 29
     public function index(PrimaNotaDataTable $dataTable)
30 30
     {
31
+        $dataTable->attivita_id = session()->get('attivita_attuale');
31 32
         return $dataTable->render('prima_nota.index');
32 33
     }
33 34
 

+ 84
- 0
app/Http/Controllers/PuntoOperatoreController.php 查看文件

@@ -0,0 +1,84 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use Illuminate\Http\Request;
6
+use App\Models\Dispositivo;
7
+use App\DataTables\PuntoOperatoreDataTable;
8
+use App\DataTables\PuntoOperatoreDataTableEditor;
9
+use Illuminate\Support\Facades\Auth;
10
+
11
+class PuntoOperatoreController extends Controller
12
+{
13
+    public static $permission_group = "Punto Operatore";
14
+    public static $permissions = [
15
+        'view-punto_operatore' => 'Vedi',
16
+        'create-punto_operatore' => 'Crea',
17
+        'edit-punto_operatore' => 'Modifica',
18
+        'delete-punto_operatore' => 'Elimina',
19
+    ];
20
+    
21
+    
22
+    public static function middleware(): array
23
+    {
24
+        return [
25
+            new Middleware('permission:view-punto_operatore', only: ['index']),
26
+            new Middleware('permission:edit-punto_operatore', only: ['toggle_is_attivo']),
27
+            new Middleware('permission:create-punto_operatore|edit-punto_operatore|delete-punto_operatore', only: ['store', 'update', 'destroy']),
28
+        ];
29
+    }
30
+    
31
+    
32
+    public function index(PuntoOperatoreDataTable $dataTable)
33
+    {
34
+        $attivita_attuale = session('attivita_attuale');
35
+        if(!$attivita_attuale){
36
+            return redirect()->route('attivita.index')
37
+            ->with('error', 'Attività non trovata');
38
+        }
39
+        $dataTable->attivita_id = $attivita_attuale;
40
+        return $dataTable->render('punto_operatore.index');
41
+    }
42
+    
43
+    
44
+    public function store(PuntoOperatoreDataTableEditor $editor)
45
+    {
46
+        $request = request();
47
+        $input = $request->all();
48
+        if($request->has('action')){
49
+            switch($input['action']){
50
+                case 'create':
51
+                    if(!Auth::user()->can('create-punto_operatore')) return;
52
+                    break;
53
+                case 'edit':
54
+                    if(!Auth::user()->can('edit-punto_operatore')) return;
55
+                    break;
56
+                case 'delete':
57
+                    if(!Auth::user()->can('delete-punto_operatore')) return;
58
+                    break;
59
+            }
60
+        }
61
+        return $editor->process($request);
62
+    }
63
+
64
+    public function toggle_is_attivo(Request $request)
65
+    {
66
+        $dispositivo = Dispositivo::find($request->get('punto_operatore_id'));
67
+        if(!$dispositivo){
68
+            return redirect()->back()->with('error', 'Punto operatore non trovato');
69
+        }
70
+
71
+        $dispositivo->is_attivo = !$dispositivo->is_attivo;
72
+        $dispositivo->save();
73
+        return response()->json(['success' => true, 'message' => 'Punto operatore ' . ($dispositivo->is_attivo ? 'attivato' : 'disattivato')]);
74
+    }
75
+
76
+    public function show(Request $request)
77
+    {
78
+        $dispositivo = Dispositivo::find($request->get('dispositivo_id'));
79
+        if(!$dispositivo){
80
+            return redirect()->back()->with('error', 'Punto operatore non trovato');
81
+        }
82
+        return view('punto_operatore.show', ['dispositivo' => $dispositivo]);
83
+    }
84
+}

+ 101
- 4
app/Http/Controllers/PuntovenditaController.php 查看文件

@@ -27,7 +27,7 @@ class PuntovenditaController extends Controller
27 27
     {
28 28
         return [
29 29
             new Middleware('permission:view-punto_vendita', only: ['index']),
30
-            new Middleware('permission:create-punto_vendita|edit-punto_vendita|delete-punto_vendita', only: ['store', 'update', 'destroy']),
30
+            new Middleware('permission:create-punto_vendita|edit-punto_vendita|delete-punto_vendita', only: ['store', 'update', 'destroy', 'edit']),
31 31
         ];
32 32
     }
33 33
     
@@ -35,7 +35,30 @@ class PuntovenditaController extends Controller
35 35
     {
36 36
         return $dataTable->render('punto_vendita.index');
37 37
     }
38
-    
38
+
39
+    public function edit(Request $request)
40
+    {
41
+        $puntoVendita = Dispositivo::with(['hasCucine', 'attivita.cucine', 'attivita.stampanti'])
42
+            ->find($request->get('punto_vendita_id'));
43
+        if(!$puntoVendita){
44
+            return redirect()->route('punto-vendita.index')
45
+            ->with('error', 'Punto di vendita non trovato');
46
+        }
47
+        return view('punto_vendita.edit', ['puntoVendita' => $puntoVendita]);
48
+    }
49
+
50
+    public function associa_cucina(Request $request)
51
+    {
52
+        $puntoVendita = Dispositivo::find($request->get('punto_vendita_id'));
53
+        if(!$puntoVendita){
54
+            return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
55
+        }
56
+        $cucine_ids = $request->get('cucine_ids');
57
+        $puntoVendita->hasCucine()->sync($cucine_ids);
58
+
59
+        return response()->json(['success' => true, 'message' => 'Cucine associate con successo']);
60
+    }
61
+
39 62
     public function store(PuntoVenditaDataTableEditor $editor)
40 63
     {
41 64
         $request = request();
@@ -65,8 +88,9 @@ class PuntovenditaController extends Controller
65 88
             ->with('error', 'Punto di vendita non trovato');
66 89
         }
67 90
 
68
-        $cucine = Cucina::where(['is_attiva' => true , 'attivita_id' => $puntoVendita->attivita_id])
69
-        ->orderBy('nome')->get();
91
+        $cucine = $puntoVendita->cucine()->where('is_attiva', true)->orderBy('nome')->get();
92
+
93
+        // dd($cucine);
70 94
 
71 95
 
72 96
 $ordine = Ordine::firstOrCreate([
@@ -167,4 +191,77 @@ $dataTable->ordine_id = $ordine->id;
167 191
             'pagamentiConteggioPerMetodo' => $pagamentiConteggioPerMetodo,
168 192
         ]);
169 193
     }
194
+
195
+    public function cerca_pre_ordine(Request $request)
196
+    {
197
+        $codice = $request->get('codice');
198
+        // $pre_ordine = \App\Models\SaltacodaOrdine::where('codice' , $codice)->first();
199
+        $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', 'like', '%PRE_' . strtoupper($codice) . '%')->first();
200
+
201
+        // Se non trovato, prova con "PRE_" come prefisso se non già presente
202
+        if (!$pre_ordine && stripos($codice, 'PRE_') !== 0) {
203
+            $pre_ordine = \App\Models\SaltacodaOrdine::where('codice', 'like', '%PRE_' . strtoupper($codice) . '%')->first();
204
+        }
205
+
206
+        if(!$pre_ordine){
207
+            return response()->json(['success' => false, 'message' => 'Pre-ordine non trovato']);
208
+        }
209
+        
210
+        if(!(Session::has('attivita_attuale') && Session::get('attivita_attuale') != null && (int) Session::get('attivita_attuale') == (int) $pre_ordine->attivita_id)){
211
+            return response()->json(['success' => false, 'message' => 'Pre-ordine non trovato']);
212
+        }
213
+        return view('punto_vendita.cassa._partials.pre_ordine', ['pre_ordine' => $pre_ordine]);
214
+
215
+    }
216
+    
217
+
218
+    public function importa_pre_ordine(Request $request) {
219
+
220
+        // dd($request->all());
221
+        $codice = $request->get('codice');
222
+        $pre_ordine = \App\Models\SaltacodaOrdine::where('codice' , $codice)->first();
223
+        if(!$pre_ordine){
224
+            return response()->json(['success' => false, 'message' => 'Pre-ordine non trovato']);
225
+        }
226
+        
227
+        if(!(Session::has('attivita_attuale') && Session::get('attivita_attuale') != null && (int) Session::get('attivita_attuale') == (int) $pre_ordine->attivita_id)){
228
+            return response()->json(['success' => false, 'message' => 'Attività non trovata']);
229
+        }
230
+
231
+        // $ordine = Ordine::where('id', $request->ordine_id)
232
+        // ->where('stato', Ordine::CARRELLO)
233
+        // ->where('dispositivo_id', $request->dispositivo_id)
234
+        // ->where('attivita_id', $request->attivita_id)
235
+        // ->first();
236
+
237
+        $ordine = Ordine::find($request->ordine_id);
238
+
239
+        if(!$ordine){
240
+            return response()->json(['success' => false, 'message' => 'Ordine non trovato']);
241
+        }
242
+
243
+        if($ordine->stato != Ordine::CARRELLO){
244
+            return response()->json(['success' => false, 'message' => 'Ordine non è in carrello']);
245
+        }
246
+
247
+        //compila ordine con i dati del pre-ordine
248
+        $ordine->info = $pre_ordine->info;
249
+        $ordine->save();
250
+        
251
+        foreach($pre_ordine->riga_ordine as $riga_ordine){
252
+            \App\Models\RigaOrdine::create([
253
+                'ordine_id' => $ordine->id,
254
+                'piatto_id' => $riga_ordine->piatto_id,
255
+                'quantita' => $riga_ordine->quantita,
256
+                'prezzo' => $riga_ordine->prezzo,
257
+                'note' => $riga_ordine->note,
258
+            ]);
259
+        }
260
+
261
+        //elimina pre-ordine
262
+        $pre_ordine->stato = \App\Models\SaltacodaOrdine::IMPORTATO;
263
+        $pre_ordine->save();
264
+
265
+        return response()->json(['success' => true, 'message' => 'Pre-ordine importato', 'data' => $pre_ordine]);
266
+    }
170 267
 }

+ 459
- 0
app/Http/Controllers/ReportController.php 查看文件

@@ -0,0 +1,459 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use App\Models\Attivita;
6
+use App\Models\Cucina;
7
+use App\Models\Ordine;
8
+use App\Models\Pagamento;
9
+use App\Models\PrimaNota;
10
+use App\Models\RigaOrdine;
11
+use Barryvdh\DomPDF\Facade\Pdf;
12
+use Carbon\Carbon;
13
+use Carbon\CarbonPeriod;
14
+use Illuminate\Http\Request;
15
+use Illuminate\Support\Facades\Auth;
16
+
17
+class ReportController extends Controller
18
+{
19
+    public static $permission_group = "Report";
20
+    public static $permissions = [
21
+        'view-report' => 'Vedi',
22
+        'create-report' => 'Crea',
23
+        'edit-report' => 'Modifica',
24
+        'delete-report' => 'Elimina',
25
+    ];
26
+    
27
+    
28
+    public static function middleware(): array
29
+    {
30
+        return [
31
+            new Middleware('permission:view-report', only: ['index']),
32
+            new Middleware('permission:create-report|edit-report|delete-report', only: ['store', 'update', 'destroy']),
33
+        ];
34
+    }
35
+    
36
+
37
+    public function index(Request $request)
38
+    {
39
+        $data = $this->buildReportData($request);
40
+
41
+        return view('report.index', $data);
42
+    }
43
+
44
+    public function exportPdf(Request $request)
45
+    {
46
+        $data = $this->buildReportData($request);
47
+        $type = strtolower((string) $request->get('type', 'movimenti'));
48
+
49
+        $allowedTypes = ['movimenti', 'incassi', 'cucine'];
50
+        if (!in_array($type, $allowedTypes, true)) {
51
+            $type = 'movimenti';
52
+        }
53
+
54
+        $pdf = Pdf::loadView('report.pdf', array_merge($data, [
55
+            'reportType' => $type,
56
+        ]))->setPaper('a4', 'portrait');
57
+
58
+        $dompdf = $pdf->getDomPDF();
59
+        $dompdf->render();
60
+
61
+        $canvas = $dompdf->getCanvas();
62
+        $fontMetrics = $dompdf->getFontMetrics();
63
+        $fontRegular = $fontMetrics->getFont('DejaVu Sans', 'normal');
64
+        $fontBold = $fontMetrics->getFont('DejaVu Sans', 'bold');
65
+
66
+        $printedAt = now()->format('d/m/Y H:i');
67
+        $headerText = sprintf(
68
+            '%s - %s',
69
+            (string) ($data['attivitaNome'] ?? 'Attivita'),
70
+            $this->resolveReportPdfTitle($type)
71
+        );
72
+
73
+        $canvas->page_script(function ($pageNumber, $pageCount, $canvas, $fontMetrics) use ($fontRegular, $fontBold, $printedAt, $headerText) {
74
+            $width = $canvas->get_width();
75
+            $height = $canvas->get_height();
76
+
77
+            // Footer: left print datetime.
78
+            $canvas->text(28, $height - 22, 'Stampa: ' . $printedAt, $fontRegular, 9, [0.35, 0.40, 0.50]);
79
+
80
+            // Footer: right page counter.
81
+            $pageText = sprintf('%d / %d', $pageNumber, $pageCount);
82
+            $pageTextWidth = $fontMetrics->getTextWidth($pageText, $fontRegular, 9);
83
+            $canvas->text($width - 28 - $pageTextWidth, $height - 22, $pageText, $fontRegular, 9, [0.35, 0.40, 0.50]);
84
+
85
+            // Header from second page onward.
86
+            if ($pageNumber > 1) {
87
+                $headerTextWidth = $fontMetrics->getTextWidth($headerText, $fontBold, 9);
88
+                $canvas->text($width - 28 - $headerTextWidth, 22, $headerText, $fontBold, 9, [0.10, 0.17, 0.28]);
89
+            }
90
+        });
91
+
92
+        $filename = sprintf(
93
+            'report-%s-%s.pdf',
94
+            $type,
95
+            now()->format('Ymd-His')
96
+        );
97
+
98
+        return response($dompdf->output(), 200, [
99
+            'Content-Type' => 'application/pdf',
100
+            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
101
+        ]);
102
+    }
103
+
104
+    private function buildReportData(Request $request): array
105
+    {
106
+        [$from, $to] = $this->resolveDateRange((string) $request->get('range', ''));
107
+        $attivitaId = session()->get('attivita_attuale');
108
+        $selectedCucinaId = (int) $request->get('cucina_id', 0);
109
+        $selectedPagamento = (string) $request->get('pagamento', 'all');
110
+
111
+        $cucine = Cucina::query()
112
+            ->when($attivitaId, function ($query) use ($attivitaId) {
113
+                $query->where('attivita_id', $attivitaId);
114
+            })
115
+            ->orderBy('nome')
116
+            ->get(['id', 'nome']);
117
+
118
+        $pagamentiCollection = Pagamento::query()
119
+            ->with(['metodo_pagamento', 'ordine.righe_ordine.piatto'])
120
+            ->when($attivitaId, function ($query) use ($attivitaId) {
121
+                $query->where('attivita_id', $attivitaId);
122
+            })
123
+            ->when($selectedPagamento !== '' && $selectedPagamento !== 'all', function ($query) use ($selectedPagamento) {
124
+                $query->whereHas('metodo_pagamento', function ($q) use ($selectedPagamento) {
125
+                    $q->where('tipo', $selectedPagamento);
126
+                });
127
+            })
128
+            ->when($selectedCucinaId > 0, function ($query) use ($selectedCucinaId) {
129
+                $query->whereHas('ordine.righe_ordine.piatto', function ($q) use ($selectedCucinaId) {
130
+                    $q->where('cucina_id', $selectedCucinaId);
131
+                });
132
+            })
133
+            ->whereBetween('created_at', [$from->copy()->startOfDay(), $to->copy()->endOfDay()])
134
+            ->orderByDesc('created_at')
135
+            ->get();
136
+
137
+        $movimentiCollection = PrimaNota::query()
138
+            ->with(['pagamento.metodo_pagamento', 'ordine.righe_ordine.piatto'])
139
+            ->when($attivitaId, function ($query) use ($attivitaId) {
140
+                $query->where('attivita_id', $attivitaId);
141
+            })
142
+            ->when($selectedPagamento !== '' && $selectedPagamento !== 'all', function ($query) use ($selectedPagamento) {
143
+                $query->whereHas('pagamento.metodo_pagamento', function ($q) use ($selectedPagamento) {
144
+                    $q->where('tipo', $selectedPagamento);
145
+                });
146
+            })
147
+            ->when($selectedCucinaId > 0, function ($query) use ($selectedCucinaId) {
148
+                $query->whereHas('ordine.righe_ordine.piatto', function ($q) use ($selectedCucinaId) {
149
+                    $q->where('cucina_id', $selectedCucinaId);
150
+                });
151
+            })
152
+            ->whereBetween('created_at', [$from->copy()->startOfDay(), $to->copy()->endOfDay()])
153
+            ->orderByDesc('created_at')
154
+            ->get();
155
+
156
+        if ($movimentiCollection->isNotEmpty()) {
157
+            $movimenti = $movimentiCollection->map(function ($movimento) {
158
+                $tipoRaw = strtolower((string) $movimento->tipo_movimento);
159
+                $isUscita = $tipoRaw === 'uscita' || ((float) $movimento->importo) < 0;
160
+                $tipo = $isUscita ? 'uscita' : 'entrata';
161
+
162
+                $metodoPagamento = $movimento->pagamento?->metodo_pagamento;
163
+                $metodo = $metodoPagamento?->nome ?? $metodoPagamento?->tipo ?? 'N/D';
164
+
165
+                $categoria = $movimento->riferimento;
166
+                if (empty($categoria)) {
167
+                    if (!empty($movimento->ordine_id)) {
168
+                        $categoria = 'Ordine';
169
+                    } elseif (!empty($movimento->prenotazione_id)) {
170
+                        $categoria = 'Prenotazione';
171
+                    } else {
172
+                        $categoria = 'Movimento';
173
+                    }
174
+                }
175
+
176
+                $causaleBase = $movimento->causale;
177
+                if (empty($causaleBase)) {
178
+                    $causaleBase = !empty($movimento->pagamento_id)
179
+                        ? 'Pagamento #' . $movimento->pagamento_id
180
+                        : 'Movimento #' . $movimento->id;
181
+                }
182
+
183
+                $riferimenti = $this->resolveMovimentoRiferimenti($movimento);
184
+                $causale = $riferimenti !== ''
185
+                    ? $riferimenti . ' - ' . $causaleBase
186
+                    : $causaleBase;
187
+
188
+                return [
189
+                    'timestamp' => optional($movimento->created_at)->format('Y-m-d H:i:s'),
190
+                    'tipo' => $tipo,
191
+                    'importo' => abs((float) $movimento->importo),
192
+                    'categoria' => $categoria,
193
+                    'causale' => $causale,
194
+                    'metodo' => $metodo,
195
+                ];
196
+            })->values();
197
+        } else {
198
+            $movimenti = $pagamentiCollection->map(function ($pagamento) {
199
+                $metodoPagamento = $pagamento->metodo_pagamento;
200
+                $metodo = $metodoPagamento?->nome ?? $metodoPagamento?->tipo ?? 'N/D';
201
+
202
+                return [
203
+                    'timestamp' => optional($pagamento->created_at)->format('Y-m-d H:i:s'),
204
+                    'tipo' => 'entrata',
205
+                    'importo' => abs((float) $pagamento->importo),
206
+                    'categoria' => 'Pagamento',
207
+                    'causale' => $pagamento->causale ?: ('Pagamento #' . $pagamento->id),
208
+                    'metodo' => $metodo,
209
+                ];
210
+            })->values();
211
+        }
212
+
213
+        $totEntrate = $movimenti->where('tipo', 'entrata')->sum('importo');
214
+        $totUscite = $movimenti->where('tipo', 'uscita')->sum('importo');
215
+        $saldo = $totEntrate - $totUscite;
216
+
217
+        $attivitaNome = Attivita::find($attivitaId)?->nome ?? 'Attivita';
218
+        $periodoLabel = $from->format('d/m/Y') . ' - ' . $to->format('d/m/Y');
219
+
220
+        $incassoPerGiornoMap = $pagamentiCollection
221
+            ->groupBy(function ($pagamento) {
222
+                return optional($pagamento->created_at)->format('Y-m-d');
223
+            })
224
+            ->map(function ($items) {
225
+                return (float) $items->sum(function ($pagamento) {
226
+                    return (float) ($pagamento->importo ?? 0);
227
+                });
228
+            });
229
+
230
+        $incassoChartLabels = [];
231
+        $incassoChartSeries = [];
232
+        foreach (CarbonPeriod::create($from->copy()->startOfDay(), $to->copy()->startOfDay()) as $date) {
233
+            $dateKey = $date->format('Y-m-d');
234
+            $incassoChartLabels[] = $date->format('d/m');
235
+            $incassoChartSeries[] = (float) ($incassoPerGiornoMap[$dateKey] ?? 0);
236
+        }
237
+
238
+        $ordiniCollection = Ordine::query()
239
+            ->when($attivitaId, function ($query) use ($attivitaId) {
240
+                $query->where('attivita_id', $attivitaId);
241
+            })
242
+            ->whereBetween('created_at', [$from->copy()->startOfDay(), $to->copy()->endOfDay()])
243
+            ->when($selectedPagamento !== '' && $selectedPagamento !== 'all', function ($query) use ($selectedPagamento) {
244
+                $query->whereHas('pagamento.metodo_pagamento', function ($metodoQuery) use ($selectedPagamento) {
245
+                    $metodoQuery->where('tipo', $selectedPagamento);
246
+                });
247
+            })
248
+            ->when($selectedCucinaId > 0, function ($query) use ($selectedCucinaId) {
249
+                $query->whereHas('righe_ordine.piatto', function ($q) use ($selectedCucinaId) {
250
+                    $q->where('cucina_id', $selectedCucinaId);
251
+                });
252
+            })
253
+            ->get(['id', 'created_at']);
254
+
255
+        $dayLabels = [1 => 'Lun', 2 => 'Mar', 3 => 'Mer', 4 => 'Gio', 5 => 'Ven', 6 => 'Sab', 7 => 'Dom'];
256
+        $dayAxis = array_values($dayLabels);
257
+        $hourLabels = collect(range(0, 23))->map(function ($hour) {
258
+            return str_pad((string) $hour, 2, '0', STR_PAD_LEFT) . ':00';
259
+        })->values()->all();
260
+
261
+        $heatmapMatrix = [];
262
+        foreach ($hourLabels as $hourLabel) {
263
+            $heatmapMatrix[$hourLabel] = array_fill(0, count($dayAxis), 0);
264
+        }
265
+
266
+        foreach ($ordiniCollection as $ordine) {
267
+            if (!$ordine->created_at) {
268
+                continue;
269
+            }
270
+
271
+            $date = Carbon::parse($ordine->created_at);
272
+            $dayIndex = $date->dayOfWeekIso - 1; // Lun=0 ... Dom=6
273
+            $hourLabel = str_pad((string) $date->hour, 2, '0', STR_PAD_LEFT) . ':00';
274
+
275
+            if (!isset($heatmapMatrix[$hourLabel], $heatmapMatrix[$hourLabel][$dayIndex])) {
276
+                continue;
277
+            }
278
+
279
+            $heatmapMatrix[$hourLabel][$dayIndex]++;
280
+        }
281
+
282
+        $heatmapSeries = collect($hourLabels)->map(function ($hourLabel) use ($heatmapMatrix) {
283
+            return [
284
+                'name' => $hourLabel,
285
+                'data' => $heatmapMatrix[$hourLabel] ?? array_fill(0, 7, 0),
286
+            ];
287
+        })->values();
288
+
289
+        $righeCucinaCollection = RigaOrdine::query()
290
+            ->with(['piatto.cucina', 'ordine'])
291
+            ->whereHas('ordine', function ($query) use ($attivitaId, $from, $to, $selectedPagamento) {
292
+                $query
293
+                    ->when($attivitaId, function ($q) use ($attivitaId) {
294
+                        $q->where('attivita_id', $attivitaId);
295
+                    })
296
+                    ->whereBetween('created_at', [$from->copy()->startOfDay(), $to->copy()->endOfDay()])
297
+                    ->when($selectedPagamento !== '' && $selectedPagamento !== 'all', function ($q) use ($selectedPagamento) {
298
+                        $q->whereHas('pagamento.metodo_pagamento', function ($metodoQuery) use ($selectedPagamento) {
299
+                            $metodoQuery->where('tipo', $selectedPagamento);
300
+                        });
301
+                    });
302
+            })
303
+            ->when($selectedCucinaId > 0, function ($query) use ($selectedCucinaId) {
304
+                $query->whereHas('piatto', function ($q) use ($selectedCucinaId) {
305
+                    $q->where('cucina_id', $selectedCucinaId);
306
+                });
307
+            })
308
+            ->get();
309
+
310
+        $cucineReportRows = $righeCucinaCollection
311
+            ->groupBy(function ($riga) {
312
+                return $riga->piatto?->cucina_id ?: 0;
313
+            })
314
+            ->map(function ($items, $cucinaId) {
315
+                $first = $items->first();
316
+                $cucinaNome = $first?->piatto?->cucina?->nome ?? ('Cucina #' . $cucinaId);
317
+
318
+                return [
319
+                    'cucina' => $cucinaNome,
320
+                    'ordini' => $items->pluck('ordine_id')->filter()->unique()->count(),
321
+                    'righe' => $items->count(),
322
+                    'quantita' => (int) $items->sum(function ($riga) {
323
+                        return (int) ($riga->quantita ?? 0);
324
+                    }),
325
+                    'incasso' => (float) $items->sum(function ($riga) {
326
+                        $qta = (float) ($riga->quantita ?? 0);
327
+                        $prezzo = (float) ($riga->prezzo ?? 0);
328
+                        return $qta * $prezzo;
329
+                    }),
330
+                ];
331
+            })
332
+            ->sortByDesc('incasso')
333
+            ->values();
334
+
335
+        $topPiattiRows = $righeCucinaCollection
336
+            ->groupBy(function ($riga) {
337
+                return $riga->piatto_id ?: 0;
338
+            })
339
+            ->map(function ($items) {
340
+                $first = $items->first();
341
+                return [
342
+                    'piatto' => $first?->piatto?->nome ?? 'Piatto',
343
+                    'quantita' => (int) $items->sum(function ($riga) {
344
+                        return (int) ($riga->quantita ?? 0);
345
+                    }),
346
+                ];
347
+            })
348
+            ->sortByDesc('quantita')
349
+            ->take(8)
350
+            ->values();
351
+
352
+        $paymentBreakdownRows = $pagamentiCollection
353
+            ->groupBy(function ($pagamento) {
354
+                return $pagamento->metodo_pagamento?->nome
355
+                    ?? $pagamento->metodo_pagamento?->tipo
356
+                    ?? 'N/D';
357
+            })
358
+            ->map(function ($items, $metodo) use ($totEntrate) {
359
+                $importo = (float) $items->sum(function ($pagamento) {
360
+                    return (float) ($pagamento->importo ?? 0);
361
+                });
362
+                return [
363
+                    'metodo' => (string) $metodo,
364
+                    'count' => $items->count(),
365
+                    'importo' => $importo,
366
+                    'percent' => $totEntrate > 0 ? round(($importo / $totEntrate) * 100, 1) : 0,
367
+                ];
368
+            })
369
+            ->sortByDesc('importo')
370
+            ->values();
371
+
372
+        $ordiniCount = $ordiniCollection->count();
373
+        $ticketMedio = $ordiniCount > 0 ? ((float) $totEntrate / $ordiniCount) : 0;
374
+        $coperti = (int) $righeCucinaCollection->sum(function ($riga) {
375
+            return (int) ($riga->quantita ?? 0);
376
+        });
377
+
378
+        return [
379
+            'movimenti' => $movimenti,
380
+            'totEntrate' => $totEntrate,
381
+            'totUscite' => $totUscite,
382
+            'saldo' => $saldo,
383
+            'attivitaNome' => $attivitaNome,
384
+            'periodoLabel' => $periodoLabel,
385
+            'rangeDateFrom' => $from->format('Y-m-d'),
386
+            'rangeDateTo' => $to->format('Y-m-d'),
387
+            'cucine' => $cucine,
388
+            'cucineReportRows' => $cucineReportRows,
389
+            'selectedCucinaId' => $selectedCucinaId,
390
+            'selectedPagamento' => $selectedPagamento,
391
+            'kpi' => [
392
+                'ordini' => $ordiniCount,
393
+                'incasso' => (float) $totEntrate,
394
+                'ticket_medio' => (float) $ticketMedio,
395
+                'coperti' => $coperti,
396
+            ],
397
+            'incassoChartLabels' => $incassoChartLabels,
398
+            'incassoChartSeries' => $incassoChartSeries,
399
+            'heatmapDayLabels' => $dayAxis,
400
+            'heatmapSeries' => $heatmapSeries,
401
+            'topPiattiLabels' => $topPiattiRows->pluck('piatto')->values(),
402
+            'topPiattiSeries' => $topPiattiRows->pluck('quantita')->values(),
403
+            'paymentBreakdownRows' => $paymentBreakdownRows,
404
+        ];
405
+    }
406
+
407
+    private function resolveDateRange(string $range): array
408
+    {
409
+        $start = now()->startOfMonth();
410
+        $end = now()->endOfDay();
411
+
412
+        if (!empty($range) && str_contains($range, ' to ')) {
413
+            [$fromRaw, $toRaw] = array_map('trim', explode(' to ', $range, 2));
414
+            try {
415
+                $start = Carbon::parse($fromRaw)->startOfDay();
416
+                $end = Carbon::parse($toRaw)->endOfDay();
417
+            } catch (\Throwable $e) {
418
+                // Keep fallback defaults on parse errors.
419
+            }
420
+        }
421
+
422
+        return [$start, $end];
423
+    }
424
+
425
+    private function resolveReportPdfTitle(string $type): string
426
+    {
427
+        return match ($type) {
428
+            'incassi' => 'Report Incassi',
429
+            'cucine' => 'Report Cucine',
430
+            default => 'Movimenti in EUR',
431
+        };
432
+    }
433
+
434
+    private function resolveMovimentoRiferimenti(PrimaNota $movimento): string
435
+    {
436
+        $riferimenti = [];
437
+
438
+        if (!empty($movimento->ordine_id)) {
439
+            $riferimenti[] = 'Ordine #' . $movimento->ordine_id;
440
+        }
441
+        if (!empty($movimento->pagamento_id)) {
442
+            $riferimenti[] = 'Pagamento #' . $movimento->pagamento_id;
443
+        }
444
+        if (!empty($movimento->fornitore_id)) {
445
+            $fornitoreNome = trim((string) ($movimento->fornitore?->nome ?? ''));
446
+            $riferimenti[] = $fornitoreNome !== ''
447
+                ? 'Fornitore: ' . $fornitoreNome
448
+                : 'Fornitore #' . $movimento->fornitore_id;
449
+        }
450
+        if (!empty($movimento->prenotazione_id)) {
451
+            $riferimenti[] = 'Prenotazione #' . $movimento->prenotazione_id;
452
+        }
453
+        if (!empty($movimento->evento_id)) {
454
+            $riferimenti[] = 'Evento #' . $movimento->evento_id;
455
+        }
456
+
457
+        return implode(' · ', $riferimenti);
458
+    }
459
+}

+ 190
- 0
app/Http/Controllers/RigaOrdineController.php 查看文件

@@ -3,6 +3,9 @@
3 3
 namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6
+use Illuminate\Database\Eloquent\Builder;
7
+use App\Models\Dispositivo;
8
+use App\Models\MonitorHasContenuto;
6 9
 use App\Models\RigaOrdine;
7 10
 
8 11
 class RigaOrdineController extends Controller
@@ -32,6 +35,193 @@ class RigaOrdineController extends Controller
32 35
         return response()->json(['success' => false, 'message' => 'ID non valido']);
33 36
         
34 37
     }
38
+
39
+    public function lista_da_chiamare(Request $request){
40
+        [$attivitaId, $dispositivo, $cucinaId, $errorResponse] = $this->resolveOperatoreContext($request);
41
+        if($errorResponse){
42
+            return $errorResponse;
43
+        }
44
+
45
+        $range = $request->get('range', '1h');
46
+
47
+        $righeQuery = RigaOrdine::query()
48
+            ->with(['piatto', 'ordine'])
49
+            ->where('stato', RigaOrdine::ORDINATO)
50
+            ->whereHas('piatto', function($query) use ($cucinaId){
51
+                $query->where('cucina_id', $cucinaId);
52
+            })
53
+            ->whereHas('ordine', function($query) use ($attivitaId){
54
+                $query->where('attivita_id', $attivitaId);
55
+            })
56
+            ->orderBy('created_at', 'asc');
57
+
58
+        $this->applyRangeFilter($righeQuery, $range, 'created_at');
59
+        $righe = $righeQuery->get();
60
+
61
+        return response()->json([
62
+            'success' => true,
63
+            'range' => $range,
64
+            'data' => $righe->map(function($riga){
65
+                return [
66
+                    'id' => $riga->id,
67
+                    'ordine_id' => $riga->ordine_id,
68
+                    'piatto' => $riga->piatto?->nome ?? 'Piatto',
69
+                    'quantita' => $riga->quantita,
70
+                    'stato' => $riga->stato,
71
+                ];
72
+            })->values(),
73
+        ]);
74
+    }
75
+
76
+    public function lista_chiamate(Request $request){
77
+        // dd($request->all());
78
+        [$attivitaId, $dispositivo, $cucinaId, $errorResponse] = $this->resolveOperatoreContext($request);
79
+        if($errorResponse){
80
+            return $errorResponse;
81
+        }
82
+
83
+        $range = $request->get('range', '1h');
84
+
85
+        $righeQuery = RigaOrdine::query()
86
+            ->with(['piatto', 'ordine'])
87
+            ->where('stato', RigaOrdine::CHIAMATO)
88
+            ->whereHas('piatto', function($query) use ($cucinaId){
89
+                $query->where('cucina_id', $cucinaId);
90
+            })
91
+            ->whereHas('ordine', function($query) use ($attivitaId){
92
+                $query->where('attivita_id', $attivitaId);
93
+            })
94
+            ->orderBy('updated_at', 'desc');
95
+
96
+        $this->applyRangeFilter($righeQuery, $range, 'updated_at');
97
+        $righe = $righeQuery->get();
98
+
99
+        return response()->json([
100
+            'success' => true,
101
+            'range' => $range,
102
+            'data' => $righe->map(function($riga){
103
+                return [
104
+                    'id' => $riga->id,
105
+                    'ordine_id' => $riga->ordine_id,
106
+                    'piatto' => $riga->piatto?->nome ?? 'Piatto',
107
+                    'quantita' => $riga->quantita,
108
+                    'stato' => $riga->stato,
109
+                ];
110
+            })->values(),
111
+        ]);
112
+    }
113
+
114
+    public function chiamata(Request $request){
115
+        [$attivitaId, $dispositivo, $cucinaId, $errorResponse] = $this->resolveOperatoreContext($request);
116
+        if($errorResponse){
117
+            return $errorResponse;
118
+        }
119
+
120
+        $riga_ordine = RigaOrdine::with(['piatto', 'ordine'])->find($request->riga_ordine_id);
121
+        if(!$riga_ordine){
122
+            return response()->json(['success' => false, 'message' => 'Riga ordine non trovata'], 404);
123
+        }
124
+
125
+        if(!$riga_ordine->piatto || (int) $riga_ordine->piatto->cucina_id !== (int) $cucinaId){
126
+            return response()->json(['success' => false, 'message' => 'Riga ordine non di competenza della cucina del dispositivo'], 403);
127
+        }
128
+
129
+        if(!$riga_ordine->ordine || (int) $riga_ordine->ordine->attivita_id !== (int) $attivitaId){
130
+            return response()->json(['success' => false, 'message' => 'Riga ordine non appartenente all\'attività'], 403);
131
+        }
132
+
133
+        if($riga_ordine->stato !== RigaOrdine::ORDINATO){
134
+            return response()->json(['success' => false, 'message' => 'Transizione non valida'], 422);
135
+        }
136
+
137
+        $riga_ordine->stato = RigaOrdine::CHIAMATO;
138
+        $riga_ordine->save();
139
+
140
+        return response()->json(['success' => true, 'message' => 'Riga ordine chiamata']);
141
+    }
142
+
143
+    public function ritiro(Request $request){
144
+        [$attivitaId, $dispositivo, $cucinaId, $errorResponse] = $this->resolveOperatoreContext($request);
145
+        if($errorResponse){
146
+            return $errorResponse;
147
+        }
148
+
149
+        $riga_ordine = RigaOrdine::with(['piatto', 'ordine'])->find($request->riga_ordine_id);
150
+        if(!$riga_ordine){
151
+            return response()->json(['success' => false, 'message' => 'Riga ordine non trovata'], 404);
152
+        }
153
+
154
+        if(!$riga_ordine->piatto || (int) $riga_ordine->piatto->cucina_id !== (int) $cucinaId){
155
+            return response()->json(['success' => false, 'message' => 'Riga ordine non di competenza della cucina del dispositivo'], 403);
156
+        }
157
+
158
+        if(!$riga_ordine->ordine || (int) $riga_ordine->ordine->attivita_id !== (int) $attivitaId){
159
+            return response()->json(['success' => false, 'message' => 'Riga ordine non appartenente all\'attività'], 403);
160
+        }
161
+
162
+        if($riga_ordine->stato !== RigaOrdine::CHIAMATO){
163
+            return response()->json(['success' => false, 'message' => 'Transizione non valida'], 422);
164
+        }
165
+
166
+        $riga_ordine->stato = RigaOrdine::RITIRATO;
167
+        $riga_ordine->save();
168
+
169
+        return response()->json(['success' => true, 'message' => 'Riga ordine ritirata']);
170
+    }
171
+
172
+    private function resolveOperatoreContext(Request $request): array{
173
+        $attivitaId = $request->attivita_id ?? session('attivita_attuale');
174
+        if(!$attivitaId){
175
+            return [null, null, null, response()->json(['success' => false, 'message' => 'Attività non trovata'], 404)];
176
+        }
177
+
178
+        $dispositivo = Dispositivo::find($request->dispositivo_id);
179
+        if(!$dispositivo){
180
+            return [null, null, null, response()->json(['success' => false, 'message' => 'Dispositivo non trovato'], 404)];
181
+        }
182
+
183
+        if((int) $dispositivo->attivita_id !== (int) $attivitaId){
184
+            return [null, null, null, response()->json(['success' => false, 'message' => 'Dispositivo non appartenente all\'attività'], 403)];
185
+        }
186
+
187
+        $cucinaId = $dispositivo->cucina_id;
188
+        if($dispositivo->tipo === Dispositivo::MONITOR){
189
+            $monitorHasContenuto = MonitorHasContenuto::query()
190
+                ->where('monitor_id', $dispositivo->id)
191
+                ->first();
192
+
193
+            if(!$monitorHasContenuto || !$monitorHasContenuto->cucina_id){
194
+                return [null, null, null, response()->json(['success' => false, 'message' => 'Monitor non associato a una cucina'], 422)];
195
+            }
196
+
197
+            $cucinaId = $monitorHasContenuto->cucina_id;
198
+        }
199
+
200
+        if(!$cucinaId){
201
+            return [null, null, null, response()->json(['success' => false, 'message' => 'Dispositivo non associato a una cucina'], 422)];
202
+        }
203
+
204
+        return [$attivitaId, $dispositivo, $cucinaId, null];
205
+    }
206
+
207
+    private function applyRangeFilter(Builder $query, string $range, string $column): void{
208
+        switch($range){
209
+            case '3h':
210
+                $query->where($column, '>=', now()->subHours(3));
211
+                break;
212
+            case 'today':
213
+                $query->whereBetween($column, [now()->startOfDay(), now()->endOfDay()]);
214
+                break;
215
+            case '1h':
216
+            default:
217
+                $query->where($column, '>=', now()->subHour());
218
+                break;
219
+        }
220
+    }
221
+
222
+
223
+
224
+
35 225
     // public function index(RigaOrdineDataTable $dataTable){
36 226
     //     return $dataTable->render('riga_ordine.index');
37 227
     // }

+ 247
- 0
app/Http/Controllers/SaltacodaController.php 查看文件

@@ -0,0 +1,247 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use Illuminate\Http\Request;
6
+use App\Models\Attivita;
7
+use App\Models\Cucina;
8
+use App\Models\Piatto;
9
+use App\Models\Saltacoda;
10
+use App\Models\SaltacodaOrdine;
11
+use App\Models\SaltacodaRigaordine;
12
+use Illuminate\Support\Str;
13
+
14
+use Illuminate\Support\Facades\Auth;
15
+
16
+
17
+class SaltacodaController extends Controller
18
+{
19
+    public static $permission_group = "Saltacoda";
20
+    public static $permissions = [
21
+        'view-saltacoda' => 'Vedi',
22
+        'create-saltacoda' => 'Crea',
23
+        'edit-saltacoda' => 'Modifica',
24
+        'delete-saltacoda' => 'Elimina',
25
+    ];
26
+
27
+    public static function middleware(): array
28
+    {
29
+        return [
30
+            new Middleware('permission:view-saltacoda', only: ['index']),
31
+            new Middleware('permission:create-saltacoda|edit-saltacoda|delete-saltacoda', only: ['store', 'update', 'destroy']),
32
+        ];
33
+    }
34
+
35
+    public function index(Request $request)
36
+    {
37
+        $attivita = Attivita::find(session()->get('attivita_attuale'));
38
+        if(!$attivita) {
39
+            return redirect()->route('dashboard')->with('error', 'Attività non trovata');
40
+        }
41
+        $saltacoda = Saltacoda::where('attivita_id', $attivita->id)->first();
42
+        
43
+        if(!$saltacoda) {
44
+            return view('saltacoda.index', ['attivita' => $attivita]);
45
+        }
46
+        return view('saltacoda.index', compact('attivita', 'saltacoda'));
47
+    }
48
+
49
+    public function attiva(Request $request)
50
+    {
51
+        $attivita = Attivita::find(session()->get('attivita_attuale'));
52
+        if(!$attivita) {
53
+            return redirect()->route('dashboard')->with('error', 'Attività non trovata');
54
+        }
55
+        $saltacoda = Saltacoda::where('attivita_id', $attivita->id)->first();
56
+        if(!$saltacoda) {
57
+            $saltacoda = Saltacoda::create([
58
+                'attivita_id' => $attivita->id,
59
+                'is_attivo' => true,
60
+            ]);
61
+    }else{
62
+        $saltacoda->is_attivo = true;
63
+        $saltacoda->save();
64
+    }
65
+        return redirect()->route('saltacoda.index')->with('success', 'Saltacoda abilitato');
66
+    }
67
+
68
+    public function store(Request $request)
69
+    {
70
+        // dd($request->all());
71
+        $request->validate([
72
+            'attivita_id' => 'required|exists:attivita,id',
73
+            'is_attivo' => 'required|boolean',
74
+            'max_ordini' => 'nullable|integer|min:0',
75
+            'info' => 'nullable|json',
76
+            'note' => 'nullable|array',
77
+            'note.*.label' => 'required_with:note|string|max:255',
78
+            'note.*.value' => 'nullable|string|max:5000',
79
+        ]);
80
+
81
+        $noteJson = collect($request->input('note', []))
82
+            ->map(fn (array $row) => [
83
+                'label' => trim((string) ($row['label'] ?? '')),
84
+                'value' => trim((string) ($row['value'] ?? '')),
85
+            ])
86
+            ->filter(fn (array $row) => $row['label'] !== '')
87
+            ->values()
88
+            ->all();
89
+
90
+        $saltacoda = Saltacoda::updateOrCreate(
91
+            ['attivita_id' => $request->attivita_id],
92
+            [
93
+                'is_attivo' => $request->is_attivo,
94
+                'max_ordini' => $request->max_ordini,
95
+                'info' => $request->info,
96
+                'note' => $noteJson !== [] ? json_encode($noteJson, JSON_UNESCAPED_UNICODE) : null,
97
+            ]
98
+        );
99
+        return redirect()->route('saltacoda.index')->with('success', 'Saltacoda salvato');
100
+    }
101
+
102
+    public function show(Request $request)
103
+    {
104
+        $attivita = Attivita::find($request->get('attivita_id'));
105
+        if(!$attivita) {
106
+            return response()->json([
107
+                'success' => false,
108
+                'message' => 'Attività non trovata'
109
+            ]);
110
+        }
111
+        
112
+        $saltacoda = Saltacoda::where('attivita_id', $attivita->id)
113
+        ->where('is_attivo', true)
114
+        ->first();
115
+        if(!$saltacoda) {
116
+            return abort(404);
117
+        }
118
+
119
+
120
+        $cucine = Cucina::query()
121
+                ->where('attivita_id', $attivita->id)
122
+                ->where('is_attiva', true)
123
+                ->with(['piatti' => function ($q) use ($attivita) {
124
+                    $q->where('attivita_id', $attivita->id)
125
+                    ->where('is_attivo', true);
126
+                }])
127
+                ->get();
128
+
129
+        $campiInfo = [];
130
+        $rawInfo = $saltacoda->info;
131
+        if (is_string($rawInfo) && $rawInfo !== '') {
132
+            $decoded = json_decode($rawInfo, true);
133
+            if (is_array($decoded)) {
134
+                foreach ($decoded as $key => $value) {
135
+                    if (is_string($value)) {
136
+                        $campiInfo[] = [
137
+                            'key' => (string) $key,
138
+                            'label' => $value,
139
+                            'type' => 'text',
140
+                            'required' => false,
141
+                        ];
142
+                        continue;
143
+                    }
144
+
145
+                    if (is_array($value)) {
146
+                        $type = $value['type'] ?? 'text';
147
+                        if (!in_array($type, ['text', 'boolean', 'time'], true)) {
148
+                            $type = 'text';
149
+                        }
150
+
151
+                        $campiInfo[] = [
152
+                            'key' => (string) $key,
153
+                            'label' => (string) ($value['label'] ?? $key),
154
+                            'type' => $type,
155
+                            'required' => (bool) ($value['required'] ?? false),
156
+                        ];
157
+                    }
158
+                }
159
+            }
160
+        }
161
+
162
+        return view('saltacoda.show', [
163
+            'attivita' => $attivita,
164
+            'cucine' => $cucine,
165
+            'campi_info' => $campiInfo,
166
+            'saltacoda_id' => $saltacoda->id,
167
+        ]);
168
+    }
169
+
170
+    public function pre_ordine_salva(Request $request)
171
+    {
172
+        $request->validate([
173
+            'saltacoda_id' => 'required|exists:saltacoda,id',
174
+            'attivita_id' => 'required|exists:attivita,id',
175
+            'riga_ordine' => 'required|array|min:1',
176
+            'riga_ordine.*.piatto_id' => 'required|exists:piatto,id',
177
+            'riga_ordine.*.qta' => 'required|integer|min:1',
178
+            'riga_ordine.*.note' => 'nullable|string|max:500',
179
+            'info_cliente' => 'nullable|array',
180
+            'idempotency_key' => 'nullable|string|max:120',
181
+        ]);
182
+
183
+        $saltacoda = Saltacoda::where('id', $request->saltacoda_id)
184
+            ->where('attivita_id', $request->attivita_id)
185
+            ->first();
186
+        if (!$saltacoda) {
187
+            return response()->json([
188
+                'success' => false,
189
+                'message' => 'Saltacoda non valida per questa attività.'
190
+            ], 422);
191
+        }
192
+
193
+// dd($request->all());
194
+
195
+        //Ordine Saltacoda
196
+        $saltacoda_ordine = SaltacodaOrdine::updateOrCreate(
197
+            ['riferimento' => $request->idempotency_key],
198
+            [
199
+                'riferimento' => $request->idempotency_key,
200
+                'attivita_id' => $request->attivita_id,
201
+                'info' => $request->info_cliente,
202
+                'prenotazione_id' => null,
203
+                'stato' => SaltacodaOrdine::PRE_ORDINE,
204
+                'pagamento_id' => null,
205
+                'attivita_id' => $request->attivita_id,
206
+                'note' => null,
207
+                'codice' => "PRE_".strtoupper(Str::random(5)),
208
+                'tipo' => null,
209
+                'prezzo' => 0,
210
+                'metodo_pagamento_id' => null,
211
+                'info' => $request->info_cliente,
212
+            ]);
213
+
214
+            //Riga Ordine Saltacoda
215
+            foreach ($request->riga_ordine as $riga) {
216
+                SaltacodaRigaordine::create([
217
+                    'saltacoda_ordine_id' => $saltacoda_ordine->id,
218
+                    'piatto_id' => $riga['piatto_id'],
219
+                    'quantita' => $riga['qta'],
220
+                    'note' => $riga['note'],
221
+                    'prezzo' => (Piatto::find($riga['piatto_id'])->prezzo*$riga['qta']),
222
+                ]);
223
+            }
224
+
225
+            //Aggiorna prezzo totale ordine
226
+            $saltacoda_ordine->prezzo = $saltacoda_ordine->riga_ordine->sum('prezzo');
227
+            $saltacoda_ordine->save();
228
+
229
+            // dd($saltacoda_ordine);
230
+            return response()->json([
231
+                'success' => true,
232
+                'message' => 'Pre-ordine salvato',
233
+                'data' => $saltacoda_ordine,
234
+            ]);
235
+
236
+
237
+    }
238
+
239
+    public function pre_ordine_show(Request $request)
240
+    {
241
+        $saltacoda_ordine = SaltacodaOrdine::where('codice', $request->get('codice'))->first();
242
+        if(!$saltacoda_ordine) {
243
+            return abort(404);
244
+        }
245
+        return view('saltacoda.pre_ordine', ['saltacoda_ordine' => $saltacoda_ordine]);
246
+    }
247
+}

+ 72
- 0
app/Http/Controllers/TestiController.php 查看文件

@@ -0,0 +1,72 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use Illuminate\Http\Request;
6
+use App\Models\Testi;
7
+use App\DataTables\TestiDataTable;
8
+use App\DataTables\TestiDataTableEditor;
9
+use Illuminate\Support\Facades\Auth;
10
+
11
+class TestiController extends Controller
12
+{
13
+    public static $permission_group = "Testi";
14
+    public static $permissions = [
15
+        'view-testi' => 'Vedi',
16
+        'create-testi' => 'Crea',
17
+        'edit-testi' => 'Modifica',
18
+        'delete-testi' => 'Elimina',
19
+        'show-testi-cliente' => 'Cliente Vede',
20
+    ];
21
+    public static function middleware(): array
22
+    {
23
+        return [
24
+            new Middleware('permission:view-testi', only: ['index']),
25
+            new Middleware('permission:create-testi|edit-testi|delete-testi', only: ['store', 'update', 'destroy']),
26
+            new Middleware('permission:show-testi-cliente', only: ['show_cliente']),
27
+        ];
28
+    }
29
+
30
+    public function index(TestiDataTable $dataTable)
31
+    {
32
+        return $dataTable->render('testi.index');
33
+    }
34
+
35
+    public function store(TestiDataTableEditor $editor){
36
+        $request = request();
37
+        $input = $request->all();
38
+        if($request->has('action')){
39
+            switch($input['action']){
40
+                case 'create':
41
+                    if(!Auth::user()->can('create-testi')) return;
42
+                    break;
43
+                case 'edit':
44
+                    if(!Auth::user()->can('edit-testi')) return;
45
+                    break;
46
+                case 'delete':
47
+                    if(!Auth::user()->can('delete-testi')) return;
48
+                    break;
49
+            }
50
+        }
51
+        return $editor->process($request);
52
+    }
53
+
54
+    public function show_cliente(Request $request)
55
+    {
56
+        switch($request->get('oggetto')){
57
+            case 'privacy':
58
+                $testi = Testi::where('ambiente', 'cliente')
59
+                ->where('tipo', 'privacy')
60
+                ->where('is_attivo', true)
61
+                ->orderBy('created_at', 'desc')
62
+                ->first();
63
+                break;
64
+            default:
65
+                $testi = Testi::find($request->get('testi_id'));
66
+                break;
67
+        }
68
+
69
+  
70
+        return view('testi.show', compact('testi'));
71
+    }
72
+}

+ 9
- 0
app/Models/AbstractModels/AbstractAttivita.php 查看文件

@@ -115,4 +115,13 @@ abstract class AbstractAttivita extends \Illuminate\Foundation\Auth\User
115 115
         return $this->hasMany('\App\Models\Cucina', 'attivita_id', 'id');
116 116
     }
117 117
 
118
+    public function testi()
119
+    {
120
+        return $this->hasMany('\App\Models\Testi', 'attivita_id', 'id');
121
+    }
122
+
123
+    public function stampanti()
124
+    {
125
+        return $this->hasMany('\App\Models\Dispositivo', 'attivita_id', 'id')->where('tipo', \App\Models\Dispositivo::STAMPANTE);
126
+    }
118 127
 }

+ 63
- 0
app/Models/AbstractModels/AbstractCategoriacontabile.php 查看文件

@@ -0,0 +1,63 @@
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 AbstractCategoriacontabile extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'categoria_contabile';
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
+        'nome' => 'string',
40
+        'descrizione' => 'string',
41
+        'is_attiva' => 'boolean',
42
+        'info' => 'json',
43
+        'created_at' => 'datetime',
44
+        'updated_at' => 'datetime'
45
+    ];
46
+    
47
+    /**  
48
+     * The attributes that are mass assignable.
49
+     * 
50
+     * @var array
51
+     */
52
+    protected $fillable = [
53
+        'id',
54
+        'nome',
55
+        'descrizione',
56
+        'is_attiva',
57
+        'info',
58
+        'created_at',
59
+        'updated_at'
60
+    ];
61
+    
62
+
63
+}

+ 17
- 0
app/Models/AbstractModels/AbstractDispositivo.php 查看文件

@@ -49,6 +49,7 @@ abstract class AbstractDispositivo extends \Illuminate\Foundation\Auth\User
49 49
         'pin_sblocco' => 'string',
50 50
         'data_apertura_dispositivo' => 'datetime',
51 51
         'data_chiusura_dispositivo' => 'datetime',
52
+        'cucina_id' => 'integer',
52 53
         'created_at' => 'datetime',
53 54
         'updated_at' => 'datetime'
54 55
     ];
@@ -73,6 +74,7 @@ abstract class AbstractDispositivo extends \Illuminate\Foundation\Auth\User
73 74
         'pin_sblocco',
74 75
         'data_apertura_dispositivo',
75 76
         'data_chiusura_dispositivo',
77
+        'cucina_id',
76 78
         'created_at',
77 79
         'updated_at'
78 80
     ];
@@ -87,4 +89,19 @@ abstract class AbstractDispositivo extends \Illuminate\Foundation\Auth\User
87 89
         return $this->belongsTo('\App\Models\Endpoint', 'endpoint_id', 'id');
88 90
     }
89 91
 
92
+    function cucina()
93
+    {
94
+        return $this->belongsTo('\App\Models\Cucina', 'cucina_id', 'id');
95
+    }
96
+
97
+    function monitor_has_contenuto()
98
+    {
99
+        return $this->hasOne('\App\Models\MonitorHasContenuto', 'monitor_id', 'id');
100
+    }
101
+
102
+    public function hasCucine()
103
+    {
104
+        return $this->belongsToMany('\App\Models\Cucina', 'dispositivo_has_cucina', 'dispositivo_id', 'cucina_id');
105
+    }
106
+
90 107
 }

+ 67
- 0
app/Models/AbstractModels/AbstractDispositivoHasCucina.php 查看文件

@@ -0,0 +1,67 @@
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 AbstractDispositivoHasCucina extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'dispositivo_has_cucina';
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
+        'dispositivo_id' => 'integer',
40
+        'cucina_id' => 'integer',
41
+        'created_at' => 'datetime',
42
+        'updated_at' => 'datetime'
43
+    ];
44
+    
45
+    /**  
46
+     * The attributes that are mass assignable.
47
+     * 
48
+     * @var array
49
+     */
50
+    protected $fillable = [
51
+        'id',
52
+        'dispositivo_id',
53
+        'cucina_id',
54
+        'created_at',
55
+        'updated_at'
56
+    ];
57
+    
58
+    function dispositivo()
59
+    {
60
+        return $this->belongsTo('\App\Models\Dispositivo', 'dispositivo_id', 'id');
61
+    }
62
+
63
+    public function cucina()
64
+    {
65
+        return $this->belongsTo('\App\Models\Cucina', 'cucina_id', 'id');
66
+    }
67
+}

+ 5
- 0
app/Models/AbstractModels/AbstractEvento.php 查看文件

@@ -83,4 +83,9 @@ abstract class AbstractEvento extends \Illuminate\Foundation\Auth\User
83 83
     {
84 84
         return $this->hasMany('\App\Models\Prenotazione', 'evento_id', 'id');
85 85
     }
86
+
87
+    public function form()
88
+    {
89
+        return $this->hasMany('\App\Models\EventoForm', 'evento_id', 'id');
90
+    }
86 91
 }

+ 99
- 0
app/Models/AbstractModels/AbstractEventoForm.php 查看文件

@@ -0,0 +1,99 @@
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 AbstractEventoForm extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'evento_form';
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
+        'evento_id' => 'integer',
40
+        'ordine_visualizzazione' => 'integer',
41
+        'label' => 'string',
42
+        'descrizione' => 'string',
43
+        'obbligatoria' => 'boolean',
44
+        'nascosta' => 'boolean',
45
+        'tipo' => 'string',
46
+        'costo' => 'decimal:2',
47
+        'posti_disponibili' => 'integer',
48
+        'nascondi_se_auth' => 'boolean',
49
+        'opzioni' => 'string',
50
+        'remote_id' => 'integer',
51
+        'posti_definiti_opzioni' => 'boolean',
52
+        'created_at' => 'datetime',
53
+        'updated_at' => 'datetime'
54
+    ];
55
+    
56
+    /**  
57
+     * The attributes that are mass assignable.
58
+     * 
59
+     * @var array
60
+     */
61
+    protected $fillable = [
62
+        'id',
63
+        'evento_id',
64
+        'ordine_visualizzazione',
65
+        'label',
66
+        'descrizione',
67
+        'obbligatoria',
68
+        'nascosta',
69
+        'tipo',
70
+        'costo',
71
+        'posti_disponibili',
72
+        'descrizione',
73
+        'nascondi_se_auth',
74
+        'opzioni',
75
+        'remote_id',
76
+        'posti_definiti_opzioni',
77
+        'created_at',
78
+        'updated_at'
79
+    ];
80
+    
81
+    public function evento()
82
+    {
83
+        return $this->belongsTo('\App\Models\Evento', 'evento_id', 'id');
84
+    }
85
+    
86
+    public function prenotazioni()
87
+    {
88
+        return $this->hasMany('\App\Models\PrenotazioneRisposta', 'evento_form_id', 'id');
89
+    }
90
+
91
+    public function opzioni_form()
92
+    {
93
+        return $this->hasMany('\App\Models\OpzioneForm', 'evento_form_id', 'id');
94
+    }
95
+    public function risposte()
96
+    {
97
+        return $this->hasMany('\App\Models\PrenotazioneRisposta', 'evento_form_id', 'id');
98
+    }
99
+}

+ 7
- 0
app/Models/AbstractModels/AbstractFornitore.php 查看文件

@@ -36,6 +36,7 @@ abstract class AbstractFornitore extends \Illuminate\Foundation\Auth\User
36 36
      */
37 37
     protected $casts = [
38 38
         'id' => 'integer',  
39
+        'attivita_id' => 'integer',
39 40
         'nome' => 'string',
40 41
         'email' => 'string',
41 42
         'telefono' => 'string',
@@ -55,6 +56,7 @@ abstract class AbstractFornitore extends \Illuminate\Foundation\Auth\User
55 56
      */
56 57
     protected $fillable = [
57 58
         'id',
59
+        'attivita_id',
58 60
         'nome',
59 61
         'email',
60 62
         'telefono',
@@ -67,4 +69,9 @@ abstract class AbstractFornitore extends \Illuminate\Foundation\Auth\User
67 69
         'updated_at'
68 70
     ];
69 71
     
72
+    public function prima_nota()
73
+    {
74
+        return $this->hasMany('\App\Models\PrimaNota', 'fornitore_id', 'id');
75
+    }
76
+    
70 77
 }

+ 84
- 0
app/Models/AbstractModels/AbstractMonitorHasContenuto.php 查看文件

@@ -0,0 +1,84 @@
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 AbstractMonitorHasContenuto extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'monitor_has_contenuto';
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
+        'monitor_id' => 'integer',
40
+        'is_bacheca' => 'boolean',
41
+        'cucina_id' => 'integer',
42
+        'contenuto_bacheca_id' => 'integer',
43
+        'bacheca_id' => 'integer',
44
+        'created_at' => 'datetime',
45
+        'updated_at' => 'datetime'
46
+    ];
47
+    
48
+    /**  
49
+     * The attributes that are mass assignable.
50
+     * 
51
+     * @var array
52
+     */
53
+    protected $fillable = [
54
+        'id',
55
+        'monitor_id',
56
+        'is_bacheca',
57
+        'cucina_id',
58
+        'contenuto_bacheca_id',
59
+        'bacheca_id',
60
+        'created_at',
61
+        'updated_at'
62
+    ];
63
+    
64
+    public function monitor()
65
+    {
66
+        return $this->belongsTo('\App\Models\Dispositivo', 'monitor_id', 'id');
67
+    }
68
+
69
+    public function cucina()    
70
+    {
71
+        return $this->belongsTo('\App\Models\Cucina', 'cucina_id', 'id');
72
+    }
73
+
74
+    public function contenuto_bacheca()
75
+    {
76
+        return $this->belongsTo('\App\Models\ContenutoBacheca', 'contenuto_bacheca_id', 'id');
77
+    }
78
+
79
+    public function bacheca()
80
+    {
81
+        return $this->belongsTo('\App\Models\Bacheca', 'bacheca_id', 'id');
82
+    }
83
+    
84
+}

+ 73
- 0
app/Models/AbstractModels/AbstractOpzioneEvento.php 查看文件

@@ -0,0 +1,73 @@
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 AbstractOpzioneEvento extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'opzione_form';
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
+        'evento_form_id' => 'integer',
40
+        'label' => 'string',
41
+        'ordine' => 'integer',
42
+        'costo' => 'decimal:2',
43
+        'limite_anno' => 'string',
44
+        'remote_id' => 'integer',
45
+        'posti_disponibili' => 'integer',
46
+        'created_at' => 'datetime',
47
+        'updated_at' => 'datetime',
48
+   
49
+    ];
50
+    
51
+    /**  
52
+     * The attributes that are mass assignable.
53
+     * 
54
+     * @var array
55
+     */
56
+    protected $fillable = [
57
+        'id',
58
+        'evento_form_id',
59
+        'label',
60
+        'ordine',
61
+        'costo',
62
+        'limite_anno',
63
+        'remote_id',
64
+        'posti_disponibili',
65
+        'created_at',
66
+        'updated_at'
67
+    ];
68
+    
69
+    public function form()
70
+    {
71
+        return $this->belongsTo('\App\Models\EventoForm', 'id', 'evento_form_id');
72
+    }
73
+}

+ 8
- 0
app/Models/AbstractModels/AbstractPrenotazione.php 查看文件

@@ -83,4 +83,12 @@ abstract class AbstractPrenotazione extends \Illuminate\Foundation\Auth\User
83 83
     {
84 84
         return $this->belongsTo('\App\Models\Cucina', 'cucina_id', 'id');
85 85
     }
86
+    public function risposte()
87
+    {
88
+        return $this->hasMany('\App\Models\PrenotazioneRisposta', 'prenotazione_id', 'id');
89
+    }
90
+    public function form()
91
+    {
92
+        return $this->hasMany('\App\Models\EventoForm', 'evento_id', 'id');
93
+    }
86 94
 }

+ 78
- 0
app/Models/AbstractModels/AbstractPrenotazioneRisposta.php 查看文件

@@ -0,0 +1,78 @@
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 AbstractPrenotazioneRisposta extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'prenotazione_risposta';
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
+        'prenotazione_id' => 'integer',
40
+        'evento_form_id' => 'integer',
41
+        'risposta' => 'string',
42
+        'remote_id' => 'integer',
43
+        'costo' => 'decimal:2',
44
+        'created_at' => 'datetime',
45
+        'updated_at' => 'datetime'
46
+   
47
+    ];
48
+    
49
+    /**  
50
+     * The attributes that are mass assignable.
51
+     * 
52
+     * @var array
53
+     */
54
+    protected $fillable = [
55
+        'id',
56
+        'prenotazione_id',
57
+        'evento_form_id',
58
+        'risposta',
59
+        'remote_id',
60
+        'costo',
61
+        'created_at',
62
+        'updated_at'
63
+    ];
64
+    
65
+    public function prenotazione()
66
+    {
67
+        return $this->belongsTo('\App\Models\Prenotazione', 'prenotazione_id', 'id');
68
+    }
69
+    
70
+    public function evento_form()
71
+    {
72
+        return $this->belongsTo('\App\Models\EventoForm', 'evento_form_id', 'id');
73
+    }
74
+    
75
+
76
+
77
+
78
+}

+ 0
- 4
app/Models/AbstractModels/AbstractPrimaNota.php 查看文件

@@ -69,10 +69,6 @@ abstract class AbstractPrimaNota extends \Illuminate\Foundation\Auth\User
69 69
         'tipo_movimento',   
70 70
         'causale',
71 71
         'stato',
72
-        'note',
73
-        'codice',
74
-        'stato_pagamento',
75
-        'metodo_pagamento',
76 72
         'created_at',
77 73
         'updated_at'
78 74
     ];

+ 2
- 0
app/Models/AbstractModels/AbstractRigaOrdine.php 查看文件

@@ -41,6 +41,7 @@ abstract class AbstractRigaOrdine extends \Illuminate\Foundation\Auth\User
41 41
         'quantita' => 'integer',
42 42
         'prezzo' => 'decimal:2',
43 43
         'note' => 'string',
44
+        'stato' => 'string',
44 45
         'created_at' => 'datetime',
45 46
         'updated_at' => 'datetime'
46 47
     ];
@@ -57,6 +58,7 @@ abstract class AbstractRigaOrdine extends \Illuminate\Foundation\Auth\User
57 58
         'quantita',
58 59
         'prezzo',
59 60
         'note',
61
+        'stato',
60 62
         'created_at',
61 63
         'updated_at'
62 64
     ];

+ 70
- 0
app/Models/AbstractModels/AbstractSaltacoda.php 查看文件

@@ -0,0 +1,70 @@
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 AbstractSaltacoda extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'saltacoda';
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
+        'attivita_id' => 'integer',
40
+        'is_attivo' => 'boolean',
41
+        'max_ordini' => 'integer',
42
+        'info' => 'string',
43
+        'note' => 'string',
44
+        'created_at' => 'datetime',
45
+        'updated_at' => 'datetime'
46
+    ];
47
+    
48
+    /**  
49
+     * The attributes that are mass assignable.
50
+     * 
51
+     * @var array
52
+     */
53
+    protected $fillable = [
54
+        'id',
55
+        'attivita_id',
56
+        'is_attivo',
57
+        'max_ordini',
58
+        'info',
59
+        'note',
60
+        'created_at',
61
+        'updated_at'
62
+    ];
63
+    
64
+    public function attivita()
65
+    {
66
+        return $this->belongsTo('\App\Models\Attivita', 'attivita_id', 'id');
67
+    }
68
+
69
+
70
+}

+ 89
- 0
app/Models/AbstractModels/AbstractSaltacodaOrdine.php 查看文件

@@ -0,0 +1,89 @@
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 AbstractSaltacodaOrdine extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'saltacoda_ordine';
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
+        'riferimento' => 'string',
40
+        'prenotazione_id' => 'integer',
41
+        'stato' => 'string',
42
+        // 'dispositivo_id' => 'integer',
43
+        'pagamento_id' => 'integer',
44
+        'attivita_id' => 'integer',
45
+        'note' => 'string',
46
+        'codice' => 'string',
47
+        'tipo' => 'string',
48
+        'prezzo' => 'decimal:2',
49
+        'metodo_pagamento_id' => 'integer',
50
+        'info' => 'array',
51
+        'created_at' => 'datetime',
52
+        'updated_at' => 'datetime',
53
+
54
+    ];
55
+    
56
+    /**  
57
+     * The attributes that are mass assignable.
58
+     * 
59
+     * @var array
60
+     */
61
+    protected $fillable = [
62
+        'id',
63
+        'riferimento',
64
+        'prenotazione_id',
65
+        'stato',
66
+        'pagamento_id',
67
+        'attivita_id',
68
+        'note',
69
+        'codice',
70
+        'tipo',
71
+        'prezzo',
72
+        'metodo_pagamento_id',
73
+        'info',
74
+        'created_at',
75
+        'updated_at',
76
+    ];
77
+    
78
+    public function attivita()
79
+    {
80
+        return $this->belongsTo('\App\Models\Attivita', 'attivita_id', 'id');
81
+    }
82
+
83
+    public function riga_ordine()
84
+    {
85
+        return $this->hasMany('\App\Models\SaltacodaRigaordine', 'saltacoda_ordine_id', 'id');
86
+    }
87
+
88
+
89
+}

+ 75
- 0
app/Models/AbstractModels/AbstractSaltacodaRigaordine.php 查看文件

@@ -0,0 +1,75 @@
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 AbstractSaltacodaRigaordine extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'saltacoda_riga_ordine';
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
+        'ordine_id' => 'integer',
40
+        'piatto_id' => 'integer',
41
+        'quantita' => 'integer',
42
+        'prezzo' => 'decimal:2',
43
+        'note' => 'string',
44
+        'stato' => 'string',
45
+        'created_at' => 'datetime',
46
+        'updated_at' => 'datetime'
47
+    ];
48
+    
49
+    /**  
50
+     * The attributes that are mass assignable.
51
+     * 
52
+     * @var array
53
+     */
54
+    protected $fillable = [
55
+        'id',
56
+        'saltacoda_ordine_id',
57
+        'piatto_id',
58
+        'quantita',
59
+        'prezzo',
60
+        'note',
61
+        'stato',
62
+        'created_at',
63
+        'updated_at'
64
+    ];
65
+    
66
+    public function saltacoda_ordine()
67
+    {
68
+        return $this->belongsTo('\App\Models\SaltacodaOrdine', 'saltacoda_ordine_id', 'id');
69
+    }
70
+
71
+    public function piatto()
72
+    {
73
+        return $this->belongsTo('\App\Models\Piatto', 'piatto_id', 'id');
74
+    }
75
+}

+ 79
- 0
app/Models/AbstractModels/AbstractTesti.php 查看文件

@@ -0,0 +1,79 @@
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 AbstractTesti extends \Illuminate\Foundation\Auth\User
10
+{
11
+    /**  
12
+     * The table associated with the model.
13
+     * 
14
+     * @var string
15
+     */
16
+    protected $table = 'testi';
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
+        'attivita_id' => 'integer',
40
+        'user_id' => 'integer',
41
+        'titolo' => 'string',
42
+        'descrizione' => 'string',
43
+        'testo' => 'string',
44
+        'ambiente' => 'string',
45
+        'tipo' => 'string',
46
+        'is_attivo' => 'boolean',
47
+        'created_at' => 'datetime',
48
+        'updated_at' => 'datetime'
49
+    ];
50
+    
51
+    /**  
52
+     * The attributes that are mass assignable.
53
+     * 
54
+     * @var array
55
+     */
56
+    protected $fillable = [
57
+        'id',
58
+        'attivita_id',
59
+        'user_id',
60
+        'titolo',
61
+        'descrizione',
62
+        'testo',
63
+        'ambiente',
64
+        'tipo',
65
+        'is_attivo',
66
+        'created_at',
67
+        'updated_at'
68
+    ];
69
+    
70
+    public function attivita()
71
+    {
72
+        return $this->belongsTo('\App\Models\Attivita', 'attivita_id', 'id');
73
+    }
74
+
75
+    public function user()
76
+    {
77
+        return $this->belongsTo('\App\Models\User', 'user_id', 'id');
78
+    }
79
+}

+ 1
- 1
app/Models/BachecaHasContenuto.php 查看文件

@@ -4,7 +4,7 @@ namespace App\Models;
4 4
 
5 5
 use Illuminate\Database\Eloquent\Model;
6 6
 
7
-class BachecaHasContenuto extends Model
7
+class BachecaHasContenuto extends AbstractBachecaHasContenuto
8 8
 {
9 9
     //
10 10
 }

+ 10
- 0
app/Models/Categoriacontabile.php 查看文件

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

+ 17
- 0
app/Models/Dispositivo.php 查看文件

@@ -11,7 +11,9 @@ class Dispositivo extends \App\Models\AbstractModels\AbstractDispositivo
11 11
     const KIOSK = 'kiosk';  // kiosk di vendita
12 12
     const CAMERIERE = 'cameriere';  // cameriere di vendita
13 13
     const MONITOR = 'monitor';  // monitor PER CHIAMATA PIATTI
14
+    const OPERATORE = 'operatore';  // operatore di chiamata piatti/ordini
14 15
     const BACHECA = 'bacheca';  // bacheca di vendita/PUBBLICITà
16
+    const SALTACODA = 'saltacoda';  // permette agli utent non autenticati di creare un ordine temporaneo
15 17
 
16 18
 public static function getTipoDispositivo(){
17 19
 
@@ -46,6 +48,16 @@ public static function getTipoDispositivo(){
46 48
             'icon' => 'bx bx-book',
47 49
             'value' => self::BACHECA,
48 50
         ],
51
+        self::OPERATORE => [
52
+            'label' => 'Operatore',
53
+            'icon' => 'bx bx-user',
54
+            'value' => self::OPERATORE,
55
+        ],
56
+        self::SALTACODA => [
57
+            'label' => 'Saltacoda',
58
+            'icon' => 'bx bx-user',
59
+            'value' => self::SALTACODA,
60
+        ],
49 61
     ]);
50 62
 }
51 63
 
@@ -94,4 +106,9 @@ public static function select2_stampante(){
94 106
 public function stampante_dispositivo(){
95 107
     return Dispositivo::find($this->url_stampante);
96 108
 }
109
+
110
+public function cucine()
111
+{
112
+    return $this->belongsToMany('\App\Models\Cucina', 'dispositivo_has_cucina', 'dispositivo_id', 'cucina_id');
113
+}
97 114
 };

+ 10
- 0
app/Models/DispositivoHasCucina.php 查看文件

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

+ 60
- 0
app/Models/EventoForm.php 查看文件

@@ -0,0 +1,60 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+
7
+class EventoForm extends \App\Models\AbstractModels\AbstractEventoForm
8
+{
9
+    const TESTO = 'text';
10
+    const NUMERO = 'number';
11
+    const DATA = 'date';
12
+    const ORA = 'ora';
13
+    const SELEZIONE = 'select';
14
+    const MULTISELEZIONE = 'multi-select';
15
+    const CHECKBOX = 'checkbox';
16
+    const RADIO = 'radio';
17
+    const ELENCO = 'elenco';
18
+
19
+    public static function getTipi()
20
+    {
21
+        return collect([
22
+            self::TESTO => ['value' => self::TESTO, 'label' => 'Testo', 'icon' => 'bx bx-text'],
23
+            self::NUMERO => ['value' => self::NUMERO, 'label' => 'Numero', 'icon' => 'bx bx-hash'],
24
+            self::DATA => ['value' => self::DATA, 'label' => 'Data', 'icon' => 'bx bx-calendar'],
25
+            self::ORA => ['value' => self::ORA, 'label' => 'Ora', 'icon' => 'bx bx-time-five'],
26
+            self::SELEZIONE => ['value' => self::SELEZIONE, 'label' => 'Selezione', 'icon' => 'bx bx-list-ul'],
27
+            self::MULTISELEZIONE => ['value' => self::MULTISELEZIONE, 'label' => 'Multiselezione', 'icon' => 'bx bx-list-check'],
28
+            self::CHECKBOX => ['value' => self::CHECKBOX, 'label' => 'Checkbox', 'icon' => 'bx bx-checkbox-checked'],
29
+            self::RADIO => ['value' => self::RADIO, 'label' => 'Radio', 'icon' => 'bx bx-radio-circle-marked'],
30
+            self::ELENCO => ['value' => self::ELENCO, 'label' => 'Elenco', 'icon' => 'bx bx-list-ul'],
31
+        ]);
32
+    }
33
+
34
+
35
+    public static function getLabel($tipo)
36
+    {
37
+        return self::getTipi()[$tipo]['label'];
38
+    }
39
+    public static function getIcona($tipo)
40
+    {
41
+        return self::getTipi()[$tipo]['icon'];
42
+    }
43
+
44
+    public function getRisposta($prenotazione_id)
45
+    {
46
+        $x = \App\Models\PrenotazioneRisposta::where('prenotazione_id', $prenotazione_id)
47
+        ->where('evento_form_id', $this->id);
48
+
49
+        switch($this->tipo){
50
+            case EventoForm::ELENCO:
51
+                return $this->opzioni_form->where('id', $x->first()->risposta)->first()->label;
52
+                break;
53
+
54
+            default:
55
+                return $x->first()->risposta;
56
+                break;
57
+        };
58
+
59
+    }
60
+}

+ 8
- 1
app/Models/MetodoPagamento.php 查看文件

@@ -89,6 +89,13 @@ class MetodoPagamento extends \App\Models\AbstractModels\AbstractMetodoPagamento
89 89
 
90 90
     public function getIcona()
91 91
     {
92
-        return self::getTipiPagamento()->firstWhere('value', $this->tipo)['icon'];
92
+        $tipo = (string) ($this->tipo ?? '');
93
+        $match = self::getTipiPagamento()->firstWhere('value', $tipo);
94
+
95
+        if (!is_array($match)) {
96
+            return 'bx-wallet';
97
+        }
98
+
99
+        return $match['icon'] ?? 'bx-wallet';
93 100
     }
94 101
 }

+ 10
- 0
app/Models/MonitorHasContenuto.php 查看文件

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

+ 10
- 0
app/Models/OpzioneForm.php 查看文件

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

+ 37
- 15
app/Models/Prenotazione.php 查看文件

@@ -7,33 +7,53 @@ use Illuminate\Database\Eloquent\Model;
7 7
 class Prenotazione extends \App\Models\AbstractModels\AbstractPrenotazione
8 8
 {
9 9
     //STATI
10
-    const STATO_IN_ATTESA = 'in_attesa';
11
-    const STATO_CONFIRMATA = 'confermata';
12
-    const STATO_ANNULLATA = 'annullata';
13
-    const STATO_COMPLETATA = 'completata';
10
+    const STATO_INVIATA = 'inviata'; //cliente ha inviato la prenotazione
11
+    const STATO_CONFERMATA = 'confermata'; //organizzatore ha confermato la prenotazione
12
+    const STATO_LISTA_ATTESA = 'lista_attesa'; //organizzatore ha messo la prenotazione in lista d'attesa
13
+    const STATO_ANNULLATA = 'annullata'; //organizzatore ha annullato la prenotazione
14
+    const STATO_CANCELLATA = 'cancellata'; //cliente ha cancellato la prenotazione
15
+    const STATO_RIFIUTATA = 'rifiutata'; //organizzatore ha rifiutato la prenotazione
14 16
 
17
+    
18
+    
15 19
     public static function getStati()
16 20
     {
17 21
         return collect([
18
-            self::STATO_IN_ATTESA => [
19
-                'label' => 'In attesa',
20
-                'class' => 'badge bg-warning text-dark',
21
-                'value' => self::STATO_IN_ATTESA,
22
+            self::STATO_INVIATA => [
23
+                'label' => 'Inviata',
24
+                'class' => 'badge bg-info',
25
+                'value' => self::STATO_INVIATA,
26
+                'message' => 'La prenotazione è stata inviata',
22 27
             ],
23
-            self::STATO_CONFIRMATA => [
28
+            self::STATO_CONFERMATA => [
24 29
                 'label' => 'Confermata',
25 30
                 'class' => 'badge bg-success',
26
-                'value' => self::STATO_CONFIRMATA,
31
+                'value' => self::STATO_CONFERMATA,
32
+                'message' => 'La prenotazione è stata confermata dall\'organizzatore',
33
+            ],
34
+            self::STATO_LISTA_ATTESA => [
35
+                'label' => 'Lista d\'attesa',
36
+                'class' => 'badge bg-warning',
37
+                'value' => self::STATO_LISTA_ATTESA,
38
+                'message' => 'La prenotazione è stata messa in lista d\'attesa',
39
+            ],
40
+            self::STATO_CANCELLATA => [
41
+                'label' => 'Cancellata',
42
+                'class' => 'badge bg-danger',
43
+                'value' => self::STATO_CANCELLATA,
44
+                'message' => 'La prenotazione è stata cancellata dal cliente',
45
+            ],
46
+            self::STATO_RIFIUTATA => [
47
+                'label' => 'Rifiutata',
48
+                'class' => 'badge bg-danger',
49
+                'value' => self::STATO_RIFIUTATA,
50
+                'message' => 'La prenotazione è stata rifiutata dall\'organizzatore',
27 51
             ],
28 52
             self::STATO_ANNULLATA => [
29 53
                 'label' => 'Annullata',
30 54
                 'class' => 'badge bg-danger',
31 55
                 'value' => self::STATO_ANNULLATA,
32
-            ],
33
-            self::STATO_COMPLETATA => [
34
-                'label' => 'Completata',
35
-                'class' => 'badge bg-primary',
36
-                'value' => self::STATO_COMPLETATA,
56
+                'message' => 'La prenotazione è stata annullata dall\'organizzatore',
37 57
             ],
38 58
         ]);
39 59
     }
@@ -42,4 +62,6 @@ class Prenotazione extends \App\Models\AbstractModels\AbstractPrenotazione
42 62
     {
43 63
         return '#'.$this->id.', '.$this->nome . ' ' . $this->cognome;
44 64
     }
65
+
66
+
45 67
 }

+ 10
- 0
app/Models/PrenotazioneRisposta.php 查看文件

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

+ 5
- 0
app/Models/PrimaNota.php 查看文件

@@ -10,6 +10,7 @@ class PrimaNota extends \App\Models\AbstractModels\AbstractPrimaNota
10 10
     const ENTRATA = 'entrata';
11 11
     const USCITA = 'uscita';
12 12
     const STORNO = 'storno';
13
+    const NOTA_CREDITO = 'nota_credito';
13 14
 
14 15
     public static function getTipiMovimento()
15 16
     {
@@ -26,6 +27,10 @@ class PrimaNota extends \App\Models\AbstractModels\AbstractPrimaNota
26 27
                 'label' => 'Storno',
27 28
                 'value' => self::STORNO,
28 29
             ],
30
+            self::NOTA_CREDITO => [
31
+                'label' => 'Nota credito',
32
+                'value' => self::NOTA_CREDITO,
33
+            ],
29 34
         ]);
30 35
     }
31 36
 }

+ 43
- 0
app/Models/RigaOrdine.php 查看文件

@@ -7,4 +7,47 @@ use Illuminate\Database\Eloquent\Model;
7 7
 class RigaOrdine extends \App\Models\AbstractModels\AbstractRigaOrdine
8 8
 {
9 9
     //
10
+    const ORDINATO = 'ordinato';
11
+    const IN_PREPARAZIONE = 'in_preparazione';
12
+    const CHIAMATO = 'chiamato';
13
+    const RITIRATO = 'ritirato';
14
+
15
+    const STATI = [
16
+        self::ORDINATO => [
17
+            'label' => 'Ordinato',
18
+            'value' => self::ORDINATO,
19
+            'descrizione' => 'Riga ordine ordinata',
20
+            'icon' => 'bx bx-check-circle',
21
+        ],
22
+        self::IN_PREPARAZIONE => [
23
+            'label' => 'In preparazione',
24
+            'value' => self::IN_PREPARAZIONE,
25
+            'descrizione' => 'Riga ordine in preparazione',
26
+            'icon' => 'bx bx-dish',
27
+        ],
28
+        self::CHIAMATO => [
29
+            'label' => 'Chiamato',
30
+            'value' => self::CHIAMATO,
31
+            'descrizione' => 'Riga ordine chiamata',
32
+            'icon' => 'bx bx-bell',
33
+        ],
34
+        self::RITIRATO => [
35
+            'label' => 'Ritirato',
36
+            'value' => self::RITIRATO,
37
+            'descrizione' => 'Riga ordine ritirata',
38
+            'icon' => 'bx bx-check-circle',
39
+        ],
40
+    ];
41
+
42
+    public static function getStati()
43
+    {
44
+        return collect(self::STATI);
45
+    }
46
+
47
+    public function getStato()
48
+    {
49
+        return self::STATI[$this->stato]['label'] ?? null;
50
+    }
51
+
52
+
10 53
 }

+ 10
- 0
app/Models/Saltacoda.php 查看文件

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

+ 12
- 0
app/Models/SaltacodaOrdine.php 查看文件

@@ -0,0 +1,12 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+
7
+class SaltacodaOrdine extends \App\Models\AbstractModels\AbstractSaltacodaOrdine
8
+{
9
+    const PRE_ORDINE = 'pre_ordine';
10
+    const PRE_PROMOSSO = 'pre_promosso';
11
+    const IMPORTATO = 'importato';
12
+}

+ 10
- 0
app/Models/SaltacodaRigaordine.php 查看文件

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

+ 10
- 0
app/Models/Testi.php 查看文件

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

+ 2
- 2
app/Observers/OrdineObserver.php 查看文件

@@ -76,8 +76,8 @@ class OrdineObserver
76 76
                 Log::error('Cucina non trovata id: '.$cucina);
77 77
                 throw new \RuntimeException('Cucina non trovata id: '.$cucina);
78 78
             }elseif($cucinaModel->stampante_id === null){
79
-                Log::error('Stampante non trovata per la cucina '.$cucina);
80
-                throw new \RuntimeException('Stampante non trovata per la cucina '.$cucina);
79
+                Log::warning('Stampante non trovata per la cucina '.$cucina.' ordine: '.$ordine->id);
80
+                // throw new \RuntimeException('Stampante non trovata per la cucina '.$cucina);
81 81
             }
82 82
 
83 83
             $printJob->fill([

+ 45
- 0
app/Observers/PagamentoObserver.php 查看文件

@@ -0,0 +1,45 @@
1
+<?php
2
+
3
+namespace App\Observers;
4
+
5
+use App\Models\Pagamento;
6
+use App\Models\PrimaNota;
7
+use Illuminate\Support\Facades\Log;
8
+
9
+class PagamentoObserver
10
+{
11
+    //
12
+    public function created(Pagamento $pagamento): void
13
+    {
14
+        //Crea prima nota di entrata
15
+        $primaNota = PrimaNota::create([
16
+            'attivita_id' => $pagamento->attivita_id,
17
+            'pagamento_id' => $pagamento->id,
18
+            'importo' => $pagamento->importo,
19
+            'tipo_movimento' => PrimaNota::ENTRATA,
20
+            'causale' => $pagamento->causale,
21
+            'ordine_id' => $pagamento->ordine_id,
22
+        ]);
23
+        $primaNota->save();
24
+    }
25
+
26
+    public function updated(Pagamento $pagamento): void
27
+    {
28
+        //
29
+    }
30
+
31
+    public function deleted(Pagamento $pagamento): void
32
+    {
33
+        //
34
+    }
35
+
36
+    public function restored(Pagamento $pagamento): void
37
+    {
38
+        //
39
+    }
40
+
41
+    public function forceDeleted(Pagamento $pagamento): void
42
+    {
43
+        //
44
+    }
45
+}

+ 4
- 1
app/Providers/AppServiceProvider.php 查看文件

@@ -5,6 +5,8 @@ namespace App\Providers;
5 5
 use App\Models\Ordine;
6 6
 use App\Observers\OrdineObserver;
7 7
 use App\Observers\DispositivoObserver;
8
+use App\Observers\PagamentoObserver;
9
+use App\Models\Pagamento;
8 10
 use App\Models\Dispositivo;
9 11
 use Illuminate\Support\ServiceProvider;
10 12
 use Illuminate\Support\Facades\Vite;
@@ -26,7 +28,8 @@ class AppServiceProvider extends ServiceProvider
26 28
   {
27 29
     Ordine::observe(OrdineObserver::class);
28 30
     Dispositivo::observe(DispositivoObserver::class);
29
-    
31
+    Pagamento::observe(PagamentoObserver::class);
32
+
30 33
     Vite::useStyleTagAttributes(function (?string $src, string $url, ?array $chunk, ?array $manifest) {
31 34
       if ($src !== null) {
32 35
         return [

+ 1
- 0
composer.json 查看文件

@@ -12,6 +12,7 @@
12 12
     "php": "^8.2",
13 13
     "barryvdh/laravel-dompdf": "^3.1",
14 14
     "elibyy/tcpdf-laravel": "^11.5",
15
+    "endroid/qr-code": "^6.1",
15 16
     "imtigger/laravel-job-status": "^1.2",
16 17
     "laravel/framework": "^12.0",
17 18
     "laravel/horizon": "^5.43",

+ 73
- 1
composer.lock 查看文件

@@ -4,7 +4,7 @@
4 4
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 5
         "This file is @generated automatically"
6 6
     ],
7
-    "content-hash": "4260f19177784cdf68518f7e3fbce431",
7
+    "content-hash": "8bbddc42f6bcfe2496ed6ef0fb591a65",
8 8
     "packages": [
9 9
         {
10 10
             "name": "bacon/bacon-qr-code",
@@ -980,6 +980,78 @@
980 980
             },
981 981
             "time": "2025-06-06T08:27:48+00:00"
982 982
         },
983
+        {
984
+            "name": "endroid/qr-code",
985
+            "version": "6.1.3",
986
+            "source": {
987
+                "type": "git",
988
+                "url": "https://github.com/endroid/qr-code.git",
989
+                "reference": "5fa534856ed95649d67c0eab0cabc03ab1d8e0e2"
990
+            },
991
+            "dist": {
992
+                "type": "zip",
993
+                "url": "https://api.github.com/repos/endroid/qr-code/zipball/5fa534856ed95649d67c0eab0cabc03ab1d8e0e2",
994
+                "reference": "5fa534856ed95649d67c0eab0cabc03ab1d8e0e2",
995
+                "shasum": ""
996
+            },
997
+            "require": {
998
+                "bacon/bacon-qr-code": "^3.0",
999
+                "php": "^8.4"
1000
+            },
1001
+            "require-dev": {
1002
+                "endroid/quality": "dev-main",
1003
+                "ext-gd": "*",
1004
+                "khanamiryan/qrcode-detector-decoder": "^2.0.3",
1005
+                "setasign/fpdf": "^1.8.2"
1006
+            },
1007
+            "suggest": {
1008
+                "ext-gd": "Enables you to write PNG images",
1009
+                "khanamiryan/qrcode-detector-decoder": "Enables you to use the image validator",
1010
+                "roave/security-advisories": "Makes sure package versions with known security issues are not installed",
1011
+                "setasign/fpdf": "Enables you to use the PDF writer"
1012
+            },
1013
+            "type": "library",
1014
+            "extra": {
1015
+                "branch-alias": {
1016
+                    "dev-main": "6.x-dev"
1017
+                }
1018
+            },
1019
+            "autoload": {
1020
+                "psr-4": {
1021
+                    "Endroid\\QrCode\\": "src/"
1022
+                }
1023
+            },
1024
+            "notification-url": "https://packagist.org/downloads/",
1025
+            "license": [
1026
+                "MIT"
1027
+            ],
1028
+            "authors": [
1029
+                {
1030
+                    "name": "Jeroen van den Enden",
1031
+                    "email": "info@endroid.nl"
1032
+                }
1033
+            ],
1034
+            "description": "Endroid QR Code",
1035
+            "homepage": "https://github.com/endroid/qr-code",
1036
+            "keywords": [
1037
+                "code",
1038
+                "endroid",
1039
+                "php",
1040
+                "qr",
1041
+                "qrcode"
1042
+            ],
1043
+            "support": {
1044
+                "issues": "https://github.com/endroid/qr-code/issues",
1045
+                "source": "https://github.com/endroid/qr-code/tree/6.1.3"
1046
+            },
1047
+            "funding": [
1048
+                {
1049
+                    "url": "https://github.com/endroid",
1050
+                    "type": "github"
1051
+                }
1052
+            ],
1053
+            "time": "2026-02-05T07:01:58+00:00"
1054
+        },
983 1055
         {
984 1056
             "name": "fruitcake/php-cors",
985 1057
             "version": "v1.4.0",

+ 1
- 1
config/app.php 查看文件

@@ -13,7 +13,7 @@ return [
13 13
     |
14 14
     */
15 15
 
16
-    'name' => env('APP_NAME', 'Laravel'),
16
+    'name' => env('APP_NAME', 'Fest'),
17 17
     'admin_password' => env('ADMIN_PASSWORD', 'admin2021'),
18 18
     'admin_email' => env('ADMIN_EMAIL', 'info@elephantech.it'),
19 19
 

+ 1
- 3
database/migrations/2026_03_23_221218_cucina.php 查看文件

@@ -23,9 +23,7 @@ return new class extends Migration
23 23
         $table->timestamps();
24 24
     });
25 25
     
26
-    Schema::table('cucina', function (Blueprint $table) {
27
-        $table->foreign('stampante_id')->references('id')->on('dispositivo')->onDelete('set null');
28
-    });
26
+
29 27
     
30 28
     }
31 29
 

+ 4
- 4
database/migrations/2026_03_23_221226_prenotazione.php 查看文件

@@ -17,11 +17,11 @@ return new class extends Migration
17 17
             $table->string('cognome');
18 18
             $table->string('email');
19 19
             $table->string('telefono');
20
-            $table->bigInteger('evento_id')->unsigned();
21
-            $table->bigInteger('cucina_id')->unsigned();
22
-            $table->string('stato');
20
+            $table->bigInteger('evento_id')->unsigned()->nullable();
21
+            $table->bigInteger('cucina_id')->unsigned()->nullable();
22
+            $table->string('stato')->nullable();
23 23
             $table->string('note')->nullable();
24
-            $table->string('codice')->unique();
24
+            $table->string('codice')->unique()->nullable();
25 25
             $table->string('stato_pagamento')->nullable();
26 26
             $table->string('metodo_pagamento')->nullable();
27 27
             $table->timestamps();

+ 3
- 6
database/migrations/2026_03_23_221233_ordine.php 查看文件

@@ -21,8 +21,8 @@ return new class extends Migration
21 21
             $table->bigInteger('attivita_id')->unsigned()->nullable();
22 22
             $table->string('note')->nullable();
23 23
             $table->string('codice')->unique()->nullable();
24
-            $table->string('pagamento_id')->unsigned()->nullable();
25 24
             $table->string('tipo')->nullable();
25
+            $table->decimal('prezzo', 10, 2)->nullable();
26 26
             $table->bigInteger('metodo_pagamento_id')->unsigned()->nullable();
27 27
             $table->json('info')->nullable();
28 28
             $table->timestamps();
@@ -30,11 +30,8 @@ return new class extends Migration
30 30
 
31 31
         Schema::table('ordine', function (Blueprint $table) {
32 32
             $table->foreign('prenotazione_id')->references('id')->on('prenotazione')->onDelete('cascade');
33
-            $table->foreign('dispositivo_id')->references('id')->on('dispositivo')->onDelete('cascade');
34
-            $table->foreign('pagamento_id')->references('id')->on('pagamento')->onDelete('cascade');
35
-            $table->foreign('attivita_id')->references('id')->on('attivita')->onDelete('cascade');
36
-            $table->foreign('pagamento_id')->references('id')->on('pagamento')->onDelete('cascade');
37
-            $table->foreign('metodo_pagamento_id')->references('id')->on('metodo_pagamento')->onDelete('cascade');
33
+            // $table->foreign('attivita_id')->references('id')->on('attivita')->onDelete('cascade');
34
+            // $table->foreign('metodo_pagamento_id')->references('id')->on('metodo_pagamento')->onDelete('cascade');
38 35
         });
39 36
     }
40 37
 

+ 8
- 8
database/migrations/2026_03_23_222735_fornitore.php 查看文件

@@ -13,14 +13,14 @@ return new class extends Migration
13 13
     {
14 14
         Schema::create('fornitore', function (Blueprint $table) {
15 15
             $table->id();
16
-            $table->string('nome');
17
-            $table->string('email');
18
-            $table->string('telefono');
19
-            $table->string('indirizzo');
20
-            $table->string('citta');
21
-            $table->string('provincia');
22
-            $table->string('cap');
23
-            $table->string('paese');
16
+            $table->string('nome')->nullable();
17
+            $table->string('email')->nullable();
18
+            $table->string('telefono')->nullable();
19
+            $table->string('indirizzo')->nullable();
20
+            $table->string('citta')->nullable();
21
+            $table->string('provincia')->nullable();
22
+            $table->string('cap')->nullable();
23
+            $table->string('paese')->nullable();
24 24
             $table->timestamps();
25 25
         });
26 26
 

+ 3
- 1
database/migrations/2026_03_23_224652_dispositivo.php 查看文件

@@ -26,7 +26,9 @@ return new class extends Migration
26 26
             $table->timestamps();
27 27
         });
28 28
 
29
-
29
+        Schema::table('cucina', function (Blueprint $table) {
30
+            $table->foreign('stampante_id')->references('id')->on('dispositivo')->onDelete('set null');
31
+        });
30 32
     }
31 33
 
32 34
     /**

+ 1
- 1
database/migrations/2026_03_25_004526_bacheca.php 查看文件

@@ -19,7 +19,7 @@ return new class extends Migration
19 19
             $table->string('colore')->nullable();
20 20
             $table->string('tipo')->nullable();
21 21
             $table->string('info')->nullable();
22
-            $table->foreignId('attivita_id')->constrained('attivita');
22
+            // $table->foreignId('attivita_id')->constrained('attivita');
23 23
             $table->boolean('is_attiva')->default(true);
24 24
             $table->timestamps();
25 25
         });

+ 8
- 0
database/migrations/2026_03_25_004544_attivita.php 查看文件

@@ -26,6 +26,14 @@ return new class extends Migration
26 26
             $table->string('slug')->nullable();
27 27
             $table->timestamps();
28 28
         });
29
+        Schema::table('ordine', function (Blueprint $table) {
30
+            $table->foreign('attivita_id')->references('id')->on('attivita')->onDelete('cascade');
31
+        });
32
+
33
+        // Schema::table('attivita', function (Blueprint $table) {
34
+        //     $table->foreign('attivita_id')->references('id')->on('attivita')->onDelete('cascade');
35
+        // });
36
+
29 37
 
30 38
     // Aggiungi il campo attivita_id e la relativa FK a più tabelle
31 39
     $gruppoTabelle = ['dispositivo', 'cucina', 'prenotazione', 'evento', 'fornitore', 'piatto', 'bacheca'];

+ 3
- 0
database/migrations/2026_03_25_212234_modifiche_alle_tabelle.php 查看文件

@@ -21,7 +21,10 @@ return new class extends Migration
21 21
         Schema::table('ordine', function (Blueprint $table) {
22 22
             $table->string('stato')->nullable()->change();
23 23
             $table->decimal('prezzo', 10, 2)->nullable()->change();
24
+            $table->foreign('dispositivo_id')->references('id')->on('dispositivo')->onDelete('cascade');
25
+
24 26
         });
27
+
25 28
     }
26 29
 
27 30
     /**

+ 4
- 0
database/migrations/2026_03_27_223801_metodo_pagamento.php 查看文件

@@ -24,6 +24,10 @@ return new class extends Migration
24 24
             $table->json('info')->nullable();
25 25
             $table->timestamps();
26 26
         });
27
+
28
+        Schema::table('ordine', function (Blueprint $table) {
29
+            $table->foreign('metodo_pagamento_id')->references('id')->on('metodo_pagamento')->onDelete('cascade');
30
+        });
27 31
     }
28 32
 
29 33
     /**

+ 3
- 0
database/migrations/2026_03_27_223809_pagamento.php 查看文件

@@ -31,6 +31,9 @@ return new class extends Migration
31 31
             $table->foreign('metodo_pagamento_id')->references('id')->on('metodo_pagamento')->onDelete('cascade');
32 32
             $table->foreign('attivita_id')->references('id')->on('attivita')->onDelete('cascade');
33 33
         });
34
+        Schema::table('ordine', function (Blueprint $table) {
35
+            $table->foreign('pagamento_id')->references('id')->on('pagamento')->onDelete('cascade');
36
+        });
34 37
     }
35 38
 
36 39
     /**

+ 32
- 0
database/migrations/2026_04_10_185625_testi.php 查看文件

@@ -0,0 +1,32 @@
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('testi', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->unsignedBigInteger('attivita_id')->nullable();
17
+            $table->unsignedBigInteger('user_id')->nullable();
18
+            $table->string('titolo');
19
+            $table->string('descrizione')->nullable();
20
+            $table->text('testo')->nullable();
21
+            $table->string('ambiente')->nullable();
22
+            $table->string('tipo')->nullable();
23
+            $table->boolean('is_attivo')->default(true);
24
+            $table->timestamps();
25
+        });
26
+
27
+        Schema::table('testi', function (Blueprint $table) {
28
+            $table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
29
+            $table->foreign('attivita_id')->references('id')->on('attivita')->onDelete('cascade');
30
+        });
31
+    }
32
+};

+ 46
- 0
database/migrations/2026_04_10_222355_evento_form.php 查看文件

@@ -0,0 +1,46 @@
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('evento_form', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->unsignedBigInteger('evento_id')->nullable();
17
+            $table->integer('ordine_visualizzazione')->default(0)->nullable();
18
+            $table->string('label', 255)->nullable();
19
+            $table->text('descrizione')->nullable();
20
+            $table->boolean('obbligatoria')->default(false)->nullable();
21
+            $table->boolean('nascosta')->default(false)->nullable();
22
+            $table->string('tipo', 255)->nullable();
23
+            $table->decimal('costo', 10, 2)->nullable();
24
+            $table->integer('posti_disponibili')->default(0)->nullable();
25
+            $table->boolean('nascondi_se_auth')->default(0)->nullable();
26
+            $table->text('opzioni')->nullable();
27
+            $table->integer('remote_id')->nullable();
28
+            $table->boolean('posti_definiti_opzioni')->default(0)->nullable();
29
+            $table->timestamps();
30
+        });
31
+
32
+        Schema::table('evento_form', function (Blueprint $table) {
33
+            $table->foreign('evento_id')->references('id')->on('evento')->onDelete('cascade');
34
+        });
35
+   
36
+
37
+    }
38
+
39
+    /**
40
+     * Reverse the migrations.
41
+     */
42
+    public function down(): void
43
+    {
44
+        Schema::dropIfExists('evento_form');
45
+    }
46
+};

+ 36
- 0
database/migrations/2026_04_10_222649_prenotazione_form_risposta.php 查看文件

@@ -0,0 +1,36 @@
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('prenotazione_risposta', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->unsignedBigInteger('prenotazione_id')->nullable();
17
+            $table->unsignedBigInteger('evento_form_id')->nullable();
18
+            $table->text('risposta')->nullable();
19
+            $table->integer('remote_id')->nullable();
20
+            $table->decimal('costo', 10, 2)->nullable();
21
+            $table->timestamps();
22
+        });
23
+        Schema::table('prenotazione_risposta', function (Blueprint $table) {
24
+            $table->foreign('prenotazione_id')->references('id')->on('prenotazione')->onDelete('cascade');
25
+            $table->foreign('evento_form_id')->references('id')->on('evento_form')->onDelete('cascade');
26
+        });
27
+    }
28
+
29
+    /**
30
+     * Reverse the migrations.
31
+     */
32
+    public function down(): void
33
+    {
34
+        Schema::dropIfExists('prenotazione_form_risposte');
35
+    }
36
+};

+ 37
- 0
database/migrations/2026_04_11_130945_opzione_form.php 查看文件

@@ -0,0 +1,37 @@
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('opzione_form', function (Blueprint $table) {
15
+            $table->bigIncrements('id');
16
+            $table->unsignedBigInteger('evento_form_id')->nullable();
17
+            $table->string('label', 255)->nullable();
18
+            $table->integer('ordine')->nullable();
19
+            $table->decimal('costo', 8, 2)->nullable();
20
+            $table->string('limite_anno', 255)->nullable();
21
+            $table->integer('remote_id')->nullable();
22
+            $table->integer('posti_disponibili')->nullable();
23
+            $table->timestamps();
24
+        });
25
+        Schema::table('opzione_form', function (Blueprint $table) {
26
+            $table->foreign('evento_form_id')->references('id')->on('evento_form')->onDelete('cascade');
27
+        });
28
+    }
29
+
30
+    /**
31
+     * Reverse the migrations.
32
+     */
33
+    public function down(): void
34
+    {
35
+        Schema::dropIfExists('opzione_form');
36
+    }
37
+};

+ 29
- 0
database/migrations/2026_04_26_105216_modifica_riga_ordine.php 查看文件

@@ -0,0 +1,29 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+use App\Models\RigaOrdine;
7
+
8
+return new class extends Migration
9
+{
10
+    /**
11
+     * Run the migrations.
12
+     */
13
+    public function up(): void
14
+    {
15
+        Schema::table('riga_ordine', function (Blueprint $table) {
16
+            $table->string('stato')->nullable()->default(RigaOrdine::ORDINATO);
17
+        });
18
+    }
19
+
20
+    /**
21
+     * Reverse the migrations.
22
+     */
23
+    public function down(): void
24
+    {
25
+        Schema::table('riga_ordine', function (Blueprint $table) {
26
+            $table->dropColumn('stato');
27
+        });
28
+    }
29
+};

+ 30
- 0
database/migrations/2026_04_26_112040_modifica_dispositivo_aggiungi_cucina.php 查看文件

@@ -0,0 +1,30 @@
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('dispositivo', function (Blueprint $table) {
15
+            $table->bigInteger('cucina_id')->unsigned()->nullable();
16
+            $table->foreign('cucina_id')->references('id')->on('cucina')->onDelete('set null');
17
+        });
18
+    }
19
+
20
+    /**
21
+     * Reverse the migrations.
22
+     */
23
+    public function down(): void
24
+    {
25
+        Schema::table('dispositivo', function (Blueprint $table) {
26
+            $table->dropForeign(['cucina_id']);
27
+            $table->dropColumn('cucina_id');
28
+        });
29
+    }
30
+};

+ 0
- 0
database/migrations/2026_04_26_115810_monitor_has_contenuto.php 查看文件


部分文件因文件數量過多而無法顯示

Loading…
取消
儲存