Explorar o código

Merge branch 'master' of http://host.webmagistri.biz:3000/parisio/iao_team

Luca Parisio hai 9 meses
pai
achega
c284289e42
Modificáronse 27 ficheiros con 2770 adicións e 566 borrados
  1. 332 0
      app/Http/Livewire/Azienda.php
  2. 31 6
      app/Http/Livewire/PaymentMethod.php
  3. 54 12
      app/Http/Livewire/Record.php
  4. 4 3
      app/Http/Livewire/RecordINOUT.php
  5. 932 112
      app/Http/Livewire/RecordOUT.php
  6. 74 0
      app/Models/Azienda.php
  7. 12 0
      app/Models/Discipline.php
  8. 20 1
      app/Models/ReceiptRow.php
  9. 6 0
      app/Models/RecordRow.php
  10. 39 0
      database/migrations/2025_04_04_101800_add_fields_discipline_table.php
  11. 68 0
      database/migrations/2025_04_04_130150_create_aziendas_table.php
  12. 28 0
      database/migrations/2025_04_04_135831_add_field_discipline_to_aziendas_table.php
  13. 260 0
      database/migrations/2025_04_07_132625_add_code_to_payment_methods_and_insert_data.php
  14. 46 0
      database/migrations/2025_04_09_000000_add_fields_to_records_rows_table.php
  15. 55 0
      database/migrations/2025_04_09_000001_add_fields_and_foreign_key_to_records_table.php
  16. 47 0
      database/migrations/2025_04_09_000002_add_data_pagamento_values_to_records_table.php
  17. 176 176
      public/assets/js/datatables.js
  18. 176 176
      public/css/datatables.js
  19. 95 0
      public/css/style.css
  20. 5 4
      resources/views/layouts/app.blade.php
  21. 58 48
      resources/views/livewire/course_list.blade.php
  22. 7 2
      resources/views/livewire/payment_method.blade.php
  23. 0 2
      resources/views/livewire/receipt.blade.php
  24. 11 11
      resources/views/livewire/records.blade.php
  25. 8 1
      resources/views/livewire/records_in_out.blade.php
  26. 215 6
      resources/views/livewire/records_out.blade.php
  27. 11 6
      routes/web.php

+ 332 - 0
app/Http/Livewire/Azienda.php

@@ -0,0 +1,332 @@
+<?php
+
+namespace App\Http\Livewire;
+
+use Livewire\Component;
+use Livewire\WithFileUploads;
+use Illuminate\Support\Str;
+
+use App\Models\Azienda as AziendaModel;
+
+class Azienda extends Component
+{
+    use WithFileUploads;
+
+    public $update = false;
+    public $azienda;
+    public $ragione_sociale;
+    public $nome_associazione;
+    public $tipologia;
+    public $discipline;
+    public $logo;
+    public $temp_logo;
+    public $sede_legale_nazione;
+    public $sede_legale_provincia;
+    public $sede_legale_comune;
+    public $sede_legale_indirizzo;
+    public $sede_legale_cap;
+    public $same_address = false;
+    public $sede_operativa_nazione;
+    public $sede_operativa_provincia;
+    public $sede_operativa_comune;
+    public $sede_operativa_indirizzo;
+    public $sede_operativa_cap;
+    public $email;
+    public $pec;
+    public $telefono;
+    public $cellulare;
+    public $partita_iva;
+    public $codice_fiscale;
+    public $codice_sdi;
+    public $chiusura_anno_fiscale;
+    public $scadenza_abbonamenti;
+    public $scadenza_pagamenti_uscita;
+
+    public $search = '';
+    public $selectedDisciplines = [];
+    public $disciplineId = '';
+    public $disciplines = [];
+    public $activeTab = 'generale';
+
+    protected $rules = [
+        'ragione_sociale' => 'required|string|max:255',
+        'email' => 'required|email|max:255',
+        'pec' => 'required|email|max:255',
+        'cellulare' => 'required|string|max:20',
+    ];
+
+    public function resetFields()
+    {
+        $this->ragione_sociale = null;
+        $this->nome_associazione = null;
+        $this->tipologia = null;
+        $this->discipline = null;
+        $this->temp_logo = null;
+
+        $this->sede_legale_nazione = null;
+        $this->sede_legale_provincia = null;
+        $this->sede_legale_comune = null;
+        $this->sede_legale_indirizzo = null;
+        $this->sede_legale_cap = null;
+
+        $this->same_address = false;
+        $this->sede_operativa_nazione = null;
+        $this->sede_operativa_provincia = null;
+        $this->sede_operativa_comune = null;
+        $this->sede_operativa_indirizzo = null;
+        $this->sede_operativa_cap = null;
+
+        $this->email = null;
+        $this->pec = null;
+        $this->telefono = null;
+        $this->cellulare = null;
+
+        $this->partita_iva = null;
+        $this->codice_fiscale = null;
+        $this->codice_sdi = null;
+
+        $this->chiusura_anno_fiscale = null;
+        $this->scadenza_abbonamenti = null;
+        $this->scadenza_pagamenti_uscita = null;
+    }
+
+    public function mount()
+    {
+        $this->azienda = AziendaModel::first();
+
+        if ($this->azienda) {
+            $this->ragione_sociale = $this->azienda->ragione_sociale;
+            $this->nome_associazione = $this->azienda->nome_associazione;
+            $this->tipologia = $this->azienda->tipologia;
+            $this->discipline = $this->azienda->discipline;
+            $this->logo = $this->azienda->logo;
+
+            $this->sede_legale_nazione = $this->azienda->sede_legale_nazione;
+            $this->sede_legale_provincia = $this->azienda->sede_legale_provincia;
+            $this->sede_legale_comune = $this->azienda->sede_legale_comune;
+            $this->sede_legale_indirizzo = $this->azienda->sede_legale_indirizzo;
+            $this->sede_legale_cap = $this->azienda->sede_legale_cap;
+
+            $this->sede_operativa_nazione = $this->azienda->sede_operativa_nazione;
+            $this->sede_operativa_provincia = $this->azienda->sede_operativa_provincia;
+            $this->sede_operativa_comune = $this->azienda->sede_operativa_comune;
+            $this->sede_operativa_indirizzo = $this->azienda->sede_operativa_indirizzo;
+            $this->sede_operativa_cap = $this->azienda->sede_operativa_cap;
+
+            $this->email = $this->azienda->email;
+            $this->pec = $this->azienda->pec;
+            $this->telefono = $this->azienda->telefono;
+            $this->cellulare = $this->azienda->cellulare;
+
+            $this->partita_iva = $this->azienda->partita_iva;
+            $this->codice_fiscale = $this->azienda->codice_fiscale;
+            $this->codice_sdi = $this->azienda->codice_sdi;
+
+            $this->chiusura_anno_fiscale = $this->azienda->chiusura_anno_fiscale;
+            $this->scadenza_abbonamenti = $this->azienda->scadenza_abbonamenti;
+            $this->scadenza_pagamenti_uscita = $this->azienda->scadenza_pagamenti_uscita;
+
+            if (
+                $this->sede_legale_nazione == $this->sede_operativa_nazione &&
+                $this->sede_legale_provincia == $this->sede_operativa_provincia &&
+                $this->sede_legale_comune == $this->sede_operativa_comune &&
+                $this->sede_legale_indirizzo == $this->sede_operativa_indirizzo &&
+                $this->sede_legale_cap == $this->sede_operativa_cap
+            ) {
+                $this->same_address = true;
+            }
+
+            if ($this->azienda && $this->azienda->disciplines) {
+                $this->selectedDisciplines = array_map('trim', explode(';', $this->azienda->disciplines));
+            }
+        } else {
+            $this->update = true;
+            $this->resetFields();
+        }
+        $this->loadDisciplines();
+    }
+
+    public function render()
+    {
+        return view('livewire.azienda');
+    }
+
+    public function updatedSameAddress()
+    {
+        if ($this->same_address) {
+            $this->sede_operativa_nazione = $this->sede_legale_nazione;
+            $this->sede_operativa_provincia = $this->sede_legale_provincia;
+            $this->sede_operativa_comune = $this->sede_legale_comune;
+            $this->sede_operativa_indirizzo = $this->sede_legale_indirizzo;
+            $this->sede_operativa_cap = $this->sede_legale_cap;
+        } else {
+            $this->sede_operativa_nazione = null;
+            $this->sede_operativa_provincia = null;
+            $this->sede_operativa_comune = null;
+            $this->sede_operativa_indirizzo = null;
+            $this->sede_operativa_cap = null;
+        }
+    }
+
+    public function updatedSedeOperativaNazione()
+    {
+        $this->checkAddressDifference();
+    }
+
+    public function updatedSedeOperativaProvincia()
+    {
+        $this->checkAddressDifference();
+    }
+
+    public function updatedSedeOperativaComune()
+    {
+        $this->checkAddressDifference();
+    }
+
+    public function updatedSedeOperativaIndirizzo()
+    {
+        $this->checkAddressDifference();
+    }
+
+    public function updatedSedeOperativaCap()
+    {
+        $this->checkAddressDifference();
+    }
+
+    public function checkAddressDifference()
+    {
+        if (
+            $this->sede_legale_nazione == $this->sede_operativa_nazione &&
+            $this->sede_legale_provincia == $this->sede_operativa_provincia &&
+            $this->sede_legale_comune == $this->sede_operativa_comune &&
+            $this->sede_legale_indirizzo == $this->sede_operativa_indirizzo &&
+            $this->sede_legale_cap == $this->sede_operativa_cap
+        ) {
+            $this->same_address = true;
+        } else {
+            $this->same_address = false;
+        }
+    }
+
+    public function setTab($tab)
+    {
+        $this->activeTab = $tab;
+    }
+
+    public function edit()
+    {
+        $this->update = true;
+    }
+
+    public function save()
+    {
+        $this->validate();
+
+        try {
+            $data = [
+                'ragione_sociale' => $this->ragione_sociale,
+                'nome_associazione' => $this->nome_associazione,
+                'tipologia' => $this->tipologia,
+                'disciplines' => implode('; ', $this->selectedDisciplines),
+
+                'sede_legale_nazione' => $this->sede_legale_nazione,
+                'sede_legale_provincia' => $this->sede_legale_provincia,
+                'sede_legale_comune' => $this->sede_legale_comune,
+                'sede_legale_indirizzo' => $this->sede_legale_indirizzo,
+                'sede_legale_cap' => $this->sede_legale_cap,
+
+                'sede_operativa_nazione' => $this->sede_operativa_nazione,
+                'sede_operativa_provincia' => $this->sede_operativa_provincia,
+                'sede_operativa_comune' => $this->sede_operativa_comune,
+                'sede_operativa_indirizzo' => $this->sede_operativa_indirizzo,
+                'sede_operativa_cap' => $this->sede_operativa_cap,
+
+                'email' => $this->email,
+                'pec' => $this->pec,
+                'telefono' => $this->telefono,
+                'cellulare' => $this->cellulare,
+
+                'partita_iva' => $this->partita_iva,
+                'codice_fiscale' => $this->codice_fiscale,
+                'codice_sdi' => $this->codice_sdi,
+
+                'chiusura_anno_fiscale' => $this->chiusura_anno_fiscale,
+                'scadenza_abbonamenti' => $this->scadenza_abbonamenti,
+                'scadenza_pagamenti_uscita' => $this->scadenza_pagamenti_uscita,
+            ];
+
+            if ($this->temp_logo) {
+                $folderName = Str::slug($this->nome_associazione);
+
+                $path = 'img/' . $folderName;
+                $fullPath = storage_path('app/public/' . $path);
+
+                if (!file_exists($fullPath)) {
+                    mkdir($fullPath, 0755, true);
+                }
+
+                $logoPath = $this->temp_logo->store($path, 'public');
+                $data['logo'] = $logoPath;
+            }
+            if ($this->azienda) {
+                $this->azienda->update($data);
+                session()->flash('message', 'Dati aziendali aggiornati con successo!');
+            } else {
+                $this->azienda = AziendaModel::create($data);
+                session()->flash('message', 'Dati aziendali creati con successo!');
+            }
+
+            $this->update = false;
+        } catch (\Exception $ex) {
+            session()->flash('error', 'Errore: ' . $ex->getMessage());
+        }
+    }
+
+    public function getSelectedDisciplineNamesProperty()
+    {
+        if (empty($this->selectedDisciplines)) {
+            return [];
+        }
+
+        return \App\Models\Discipline::whereIn('id', $this->selectedDisciplines)
+            ->pluck('name')
+            ->toArray();
+    }
+
+    public function cancel()
+    {
+        $this->resetFields();
+        $this->mount();
+        $this->update = false;
+    }
+
+    public function loadDisciplines()
+    {
+        $this->disciplines = \App\Models\Discipline::select('id', 'name')->get();
+    }
+
+    public function addDiscipline()
+    {
+        if (!empty($this->disciplineId)) {
+            $discipline = \App\Models\Discipline::find($this->disciplineId);
+
+            if ($discipline && !in_array($discipline->name, $this->selectedDisciplines)) {
+                $this->selectedDisciplines[] = $discipline->name;
+                $this->disciplineId = '';
+            }
+        }
+    }
+
+    public function removeDiscipline($index)
+    {
+        if (isset($this->selectedDisciplines[$index])) {
+            unset($this->selectedDisciplines[$index]);
+            $this->selectedDisciplines = array_values($this->selectedDisciplines);
+        }
+    }
+
+    public function updatedSearch()
+    {
+        $this->loadDisciplines();
+    }
+}

+ 31 - 6
app/Http/Livewire/PaymentMethod.php

@@ -1,13 +1,13 @@
 <?php
 
 namespace App\Http\Livewire;
-
 use Livewire\Component;
+use Illuminate\Support\Facades\Auth;
 
 class PaymentMethod extends Component
 {
     public $records, $name, $enabled, $money, $type, $corrispettivo_fiscale, $dataId, $bank_id, $update = false, $add = false;
-
+    public $paymentMethods = [];
     public $banks = array();
 
     protected $rules = [
@@ -44,11 +44,13 @@ class PaymentMethod extends Component
 
     public function mount(){
 
-        if(\Auth::user()->level != env('LEVEL_ADMIN', 0))
+        if(Auth::user()->level != env('LEVEL_ADMIN', 0))
             return redirect()->to('/dashboard');
 
-        $this->banks = \App\Models\Bank::select('id', 'name')->get();
-    }
+            $this->banks = \App\Models\Bank::select('id', 'name')->get();
+
+            // Load predefined payment methods from database
+            $this->loadPaymentMethodOptions();    }
 
     public function render()
     {
@@ -146,7 +148,30 @@ class PaymentMethod extends Component
             session()->flash('success',"Metodo pagamento eliminato");
             return redirect(request()->header('Referer'));
         }catch(\Exception $e){
-            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+            session()->flash('error','Errore (' . $e->getMessage() . ')');
         }
     }
+
+    protected function loadPaymentMethodOptions()
+    {
+        $this->paymentMethods = [
+            ['name' => 'Contanti', 'code' => 'MP01'],
+            ['name' => 'Assegno', 'code' => 'MP02'],
+            ['name' => 'Assegno circolare', 'code' => 'MP03'],
+            ['name' => 'Contanti presso Tesoreria', 'code' => 'MP04'],
+            ['name' => 'Bonifico', 'code' => 'MP05'],
+            ['name' => 'Vaglia cambiario', 'code' => 'MP06'],
+            ['name' => 'Bollettino bancario', 'code' => 'MP07'],
+            ['name' => 'Carta di credito', 'code' => 'MP08'],
+            ['name' => 'RID', 'code' => 'MP09'],
+            ['name' => 'RID utenze', 'code' => 'MP10'],
+            ['name' => 'RID veloce', 'code' => 'MP11'],
+            ['name' => 'Riba', 'code' => 'MP12'],
+            ['name' => 'MAV', 'code' => 'MP13'],
+            ['name' => 'Quietanza erario stato', 'code' => 'MP14'],
+            ['name' => 'Giroconto su conti di contabilità speciale', 'code' => 'MP15'],
+            ['name' => 'Domiciliazione bancaria', 'code' => 'MP16'],
+            ['name' => 'Domiciliazione postale', 'code' => 'MP17']
+        ];
+    }
 }

+ 54 - 12
app/Http/Livewire/Record.php

@@ -329,10 +329,24 @@ class Record extends Component
         $activeWorksheet->setCellValue('D2', "");
         foreach($this->payments as $p)
         {
-            $activeWorksheet->setCellValue($letters[$idx] . '2', "Entrate");
-            $idx++;
-            $activeWorksheet->setCellValue($letters[$idx] . '2', "Uscite");
-            $idx++;
+            if($p->type == 'ALL'){
+                $activeWorksheet->setCellValue($letters[$idx] . '2', "Entrate");
+                $idx++;
+                $activeWorksheet->setCellValue($letters[$idx] . '2', "Uscite");
+                $idx++;
+            }
+            elseif($p->type == 'IN'){
+                $activeWorksheet->setCellValue($letters[$idx] . '2', "Entrate");
+                $idx++;
+                $activeWorksheet->setCellValue($letters[$idx] . '2', "");
+                $idx++;
+            }
+            elseif($p->type == 'OUT'){
+                $activeWorksheet->setCellValue($letters[$idx] . '2', "");
+                $idx++;
+                $activeWorksheet->setCellValue($letters[$idx] . '2', "Uscite");
+                $idx++;
+            }
         }
 
         $activeWorksheet->getStyle('A1:P1')->getFont()->setBold(true);
@@ -405,17 +419,45 @@ class Record extends Component
         {
             if(isset($this->totals[$p->name]))
             {
-                $activeWorksheet->setCellValue($letters[$idx] . $count, formatPrice($this->totals[$p->name]["IN"]));
-                $idx++;
-                $activeWorksheet->setCellValue($letters[$idx] . $count, formatPrice($this->totals[$p->name]["OUT"]));
-                $idx++;
+                if($p->type == 'ALL'){
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, formatPrice($this->totals[$p->name]["IN"]));
+                    $idx++;
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, formatPrice($this->totals[$p->name]["OUT"]));
+                    $idx++;
+                }
+                elseif($p->type == 'IN'){
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, formatPrice($this->totals[$p->name]["IN"]));
+                    $idx++;
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, "");
+                    $idx++;
+                }
+                elseif($p->type == 'OUT'){
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, "");
+                    $idx++;
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, formatPrice($this->totals[$p->name]["OUT"]));
+                    $idx++;
+                }
             }
             else
             {
-                $activeWorksheet->setCellValue($letters[$idx] . $count, "0");
-                $idx++;
-                $activeWorksheet->setCellValue($letters[$idx] . $count, "0");
-                $idx++;
+                if($p->type == 'ALL'){
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, "0");
+                    $idx++;
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, "0");
+                    $idx++;
+                }
+                elseif($p->type == 'IN'){
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, "0");
+                    $idx++;
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, "");
+                    $idx++;
+                }
+                elseif($p->type == 'OUT'){
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, "");
+                    $idx++;
+                    $activeWorksheet->setCellValue($letters[$idx] . $count, "0");
+                    $idx++;
+                }
             }
         }
 

+ 4 - 3
app/Http/Livewire/RecordINOUT.php

@@ -5,6 +5,9 @@ use Livewire\Component;
 
 use PhpOffice\PhpSpreadsheet\Spreadsheet;
 use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
+use Illuminate\Support\Facades\Log;
+use SimpleXMLElement;
+use Illuminate\Support\Facades\Auth;
 
 class RecordINOUT extends Component
 {
@@ -51,7 +54,7 @@ class RecordINOUT extends Component
     public function mount()
     {
 
-        if(\Auth::user()->level != env('LEVEL_ADMIN', 0))
+        if(Auth::user()->level != env('LEVEL_ADMIN', 0))
             return redirect()->to('/dashboard');
 
         $borsellino = \App\Models\Causal::where('money', true)->first();
@@ -82,7 +85,6 @@ class RecordINOUT extends Component
 
         //$this->causalsIn = \App\Models\Causal::where('parent_id', null)->where('type', 'IN')->whereNotIn('id', $this->excludeCausals)->get();
         //$this->causalsOut = \App\Models\Causal::where('parent_id', null)->where('type', 'OUT')->whereNotIn('id', $this->excludeCausals)->get();
-
     }
 
     public function getCausalsIn($records, $indentation)
@@ -683,5 +685,4 @@ class RecordINOUT extends Component
         return $path;
 
     }
-
 }

+ 932 - 112
app/Http/Livewire/RecordOUT.php

@@ -1,14 +1,22 @@
 <?php
 
 namespace App\Http\Livewire;
+
 use Livewire\Component;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Log;
+use SimpleXMLElement;
+use Livewire\WithFileUploads;
+use Illuminate\Support\Facades\DB;
+
 
 class RecordOUT extends Component
 {
+    use WithFileUploads;
 
     protected $listeners = ['setCausal' => 'setCausal'];
 
-    public $sortField ='date';
+    public $sortField = 'date';
     public $sortAsc = false;
 
     public $typeOUT = "OUT";
@@ -24,8 +32,7 @@ class RecordOUT extends Component
 
     public function sortBy($field)
     {
-        if($this->sortField === $field)
-        {
+        if ($this->sortField === $field) {
             $this->sortAsc = ! $this->sortAsc;
         } else {
             $this->sortAsc = true;
@@ -35,15 +42,16 @@ class RecordOUT extends Component
     }
 
     public $records, $dataId, $member_id, $supplier_id,
-    $causal_id,
-    $payment_method_id,
-    $date,
-    $month,
-    $year,
-    $type,
-    $amount,
-    $note,
-    $commercial, $update = false, $add = false;
+        $causal_id,
+        $payment_method_id,
+        $date,
+        $data_pagamento,
+        $month,
+        $year,
+        $type,
+        $amount,
+        $note,
+        $commercial, $update = false, $add = false;
 
     public $filterSupplier = 0, $filterPaymentMethod = 0, $filterCausals = [], $filterFrom = '', $filterTo = '', $filterCommercial = 0;
 
@@ -63,6 +71,10 @@ class RecordOUT extends Component
     public $suppliers = array();
 
     public $rows = array();
+    public $receiptFiles = [];
+    public $selectedCausal = '';
+    public $importCausals = array();
+
 
     protected $rules = [
         'supplier_id' => 'required',
@@ -83,8 +95,7 @@ class RecordOUT extends Component
     public function getSupplierProperty()
     {
         $ret = null;
-        if ($this->supplier_id > 0)
-        {
+        if ($this->supplier_id > 0) {
             $ret = \App\Models\Supplier::findOrFail($this->supplier_id);
         }
         return $ret;
@@ -93,19 +104,21 @@ class RecordOUT extends Component
     public function getCausalProperty()
     {
         $ret = null;
-        if ($this->causal_id > 0)
-        {
+        if ($this->causal_id > 0) {
             $ret = \App\Models\Causal::findOrFail($this->causal_id);
         }
         return $ret;
     }
 
-    public function resetFields(){
+    public function resetFields()
+    {
         $this->member_id = null;
         $this->supplier_id = null;
         //$this->causal_id = null;
         $this->payment_method_id = null;
         $this->date = date("Y-m-d");
+        $this->data_pagamento = date("Y-m-d");
+
         //$this->month = date("n");
         //$this->year = date("Y");
         $this->type = 'OUT';
@@ -113,34 +126,58 @@ class RecordOUT extends Component
         //$this->amount = null;
         $this->commercial = 1;
         $this->rows = array();
-        $this->rows[] = array('causal_id' => null, 'when' => array(array('month' => date("n"), 'year' => date("Y"), 'period' => '')),  'amount' => null, 'note' => '', 'commercial' => 0);
+        $this->rows[] = array(
+            'causal_id' => null,
+            'when' => array(array('month' => date("n"), 'year' => date("Y"), 'period' => '')),
+            'amount' => null,
+            'imponibile' => null,
+            'aliquota_iva' => null,
+            'note' => '',
+            'commercial' => 0
+        );
         $this->emit('load-data-table');
     }
 
     public function getCausale($records, $indentation)
     {
-        foreach($records as $record)
-        {
+        foreach ($records as $record) {
             $this->causals[] = array('id' => $record->id, 'name' => $record->getTree());
-            if(count($record->childs))
+            if (count($record->childs))
                 $this->getCausale($record->childs, $indentation + 1);
         }
     }
 
+    public $isImportModalOpen = false;
+
+    public function openImportModal()
+    {
+        $this->isImportModalOpen = true;
+    }
+
+    public function closeImportModal()
+    {
+        $this->isImportModalOpen = false;
+        $this->reset(['selectedCausal', 'receiptFiles']);
+        $this->resetValidation();
+    }
+
     public function hydrate()
     {
         $this->emit('load-select');
+
+        if (empty($this->importCausals)) {
+            $this->loadImportCausals();
+        }
     }
 
     public function mount()
     {
 
-        if (isset($_GET["from"]))
-        {
+        if (isset($_GET["from"])) {
             $this->fromPage = $_GET["from"];
         }
 
-        if(\Auth::user()->level != env('LEVEL_ADMIN', 0))
+        if (Auth::user()->level != env('LEVEL_ADMIN', 0))
             return redirect()->to('/dashboard');
 
         $this->multiMonthFrom = date("n");
@@ -155,15 +192,33 @@ class RecordOUT extends Component
 
         $this->getCausale(\App\Models\Causal::select('id', 'name')->where('parent_id', null)->where('type', 'OUT')->orderBy('name')->get(), 0);
 
-        $this->suppliers = \App\Models\Supplier::select('name','id')->orderBy('name')->get();
+        $this->suppliers = \App\Models\Supplier::select('name', 'id')->orderBy('name')->get();
         $this->payments = \App\Models\PaymentMethod::select('id', 'name')->whereIn('type', array('ALL', 'OUT'))->where('enabled', true)->orderBy('name')->get();
+
+        $this->importCausals = [];
+        $this->loadImportCausals();
+    }
+
+    public function loadImportCausals()
+    {
+        $causals = \App\Models\Causal::select('id', 'name')
+            ->where('type', 'OUT')
+            ->orderBy('name')
+            ->get();
+
+        $this->importCausals = [];
+        foreach ($causals as $causal) {
+            $this->importCausals[] = [
+                'id' => $causal->id,
+                'name' => $causal->getTree()
+            ];
+        }
     }
 
     public function getCausal($causal)
     {
         $ret = '';
-        if ($causal > 0)
-        {
+        if ($causal > 0) {
             $ret = \App\Models\Causal::findOrFail($causal)->getTree();
         }
         return $ret;
@@ -184,41 +239,34 @@ class RecordOUT extends Component
         $this->filterCommercial = 0;
         $this->hasFilter = false;
         $this->hasFilter = false;
-
     }
 
     public function render()
     {
         $datas = [];
 
-        if (false)
-        {
-            if ($this->hasFilter)
-            {
+        if (false) {
+            if ($this->hasFilter) {
 
                 $datas = \App\Models\Record::where('type', 'OUT')->with('supplier', 'payment_method');
                 /*if ($this->filterCommercial > 0)
                 {
                     $datas = $datas->where('commercial', $this->filterCommercial == 1 ? true : false);
                 }*/
-                if ($this->filterSupplier > 0)
-                {
+                if ($this->filterSupplier > 0) {
                     $datas = $datas->where('supplier_id', $this->filterSupplier);
                 }
-                if ($this->filterPaymentMethod > 0)
-                {
+                if ($this->filterPaymentMethod > 0) {
                     $datas = $datas->where('payment_method_id', $this->filterPaymentMethod);
                 }
                 /*if (sizeof($this->filterCausals) > 0)
                 {
                     $datas = $datas->whereIn('causal_id', $this->filterCausals);
                 }*/
-                if ($this->filterFrom != '')
-                {
+                if ($this->filterFrom != '') {
                     $datas = $datas->where('date', '>=', $this->filterFrom);
                 }
-                if ($this->filterTo != '')
-                {
+                if ($this->filterTo != '') {
                     $datas = $datas->where('date', '<=', $this->filterTo);
                 }
                 //$this->records = $datas->orderBy('date', 'DESC')->get();
@@ -228,40 +276,28 @@ class RecordOUT extends Component
                 //$this->total = $this->records->sum('amount');
 
                 $this->total = 0;
-                foreach($this->records as $r)
-                {
-                    foreach($r->rows as $rr)
-                    {
+                foreach ($this->records as $r) {
+                    foreach ($r->rows as $rr) {
                         $this->total += $rr->amount;
                     }
                 }
-
-            }
-            else
-            {
-                if ($this->selectedFilter == '')
-                {
+            } else {
+                if ($this->selectedFilter == '') {
                     $this->records = \App\Models\Record::where('type', 'OUT')->with('supplier', 'payment_method')->limit(20)->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get();
-                }
-                else
-                {
-                    if ($this->selectedFilter == 0)
-                    {
+                } else {
+                    if ($this->selectedFilter == 0) {
                         $fromDate = date("Y-m-d");
                         $toDate = date("Y-m-d");
                     }
-                    if ($this->selectedFilter == 1)
-                    {
+                    if ($this->selectedFilter == 1) {
                         $fromDate = date("Y-m-01");
                         $toDate = date("Y-m-t");
                     }
-                    if ($this->selectedFilter == 2)
-                    {
+                    if ($this->selectedFilter == 2) {
                         $fromDate = date("Y-01-01");
                         $toDate = date("Y-12-31");
                     }
-                    if ($this->selectedFilter == 3)
-                    {
+                    if ($this->selectedFilter == 3) {
                         $fromDate = date("2000-01-01");
                         $toDate = date("Y-12-31");
                     }
@@ -269,8 +305,7 @@ class RecordOUT extends Component
                 }
             }
 
-            foreach($this->records as $r)
-            {
+            foreach ($this->records as $r) {
                 $r->total = $r->getTotal();
                 $r->supplier = $r->supplier ? $r->supplier->name : '';
                 $r->payment = $r->payment_method ? $r->payment_method->name : '';
@@ -290,11 +325,11 @@ class RecordOUT extends Component
         return view('livewire.records_out');
     }
 
-    public function executeMultipleAction(){
+    public function executeMultipleAction()
+    {
 
         if ($this->multipleAction == 'delete')
             $this->multipleDelete();
-
     }
 
     public function add()
@@ -302,7 +337,7 @@ class RecordOUT extends Component
 
         $this->emit('load-select');
         //if ($this->hasFilter)
-            $this->emit('hide-search');
+        $this->emit('hide-search');
         $this->resetFields();
         $this->add = true;
         $this->update = false;
@@ -321,6 +356,7 @@ class RecordOUT extends Component
                 //'causal_id' => $this->causal_id,
                 'payment_method_id' => $this->payment_method_id,
                 'date' => $this->date,
+                'data_pagamento' => $this->data_pagamento,
                 //'month' => $this->month,
                 //'year' => $this->year,
                 //'note' => $this->note,
@@ -331,17 +367,21 @@ class RecordOUT extends Component
 
             $this->dataId = $record->id;
             $tot = 0;
-            foreach($this->rows as $row)
-            {
-                foreach($row["when"] as $x => $y)
-                {
+            foreach ($this->rows as $row) {
+                foreach ($row["when"] as $x => $y) {
                     $row["when"][$x]['period'] = $row["when"][$x]['month'] . "-" . $row["when"][$x]['year'];
                 }
+                $imponibile = isset($row["imponibile"]) ? $this->currencyToDouble($row["imponibile"]) : null;
+                Log::info("Imponibile store: " . $imponibile);
+                $aliquota_iva = isset($row["aliquota_iva"]) ? floatval(str_replace('%', '', $row["aliquota_iva"])) : null;
+                Log::info("Aliquota IVA store: " . $aliquota_iva);
                 \App\Models\RecordRow::create([
                     'record_id' => $this->dataId,
                     'causal_id' => $row["causal_id"],
                     'note' => $row["note"],
                     'amount' => $this->currencyToDouble($row["amount"]),
+                    'imponibile' => $imponibile,
+                    'aliquota_iva' => $aliquota_iva,
                     'commercial' => $row["commercial"],
                     'when' => json_encode($row["when"])
                 ]);
@@ -350,32 +390,34 @@ class RecordOUT extends Component
             $record->amount = $tot;
             $record->save();
 
-            session()->flash('success','Movimento creato');
+            session()->flash('success', 'Movimento creato');
             $this->resetFields();
             $this->add = false;
             $this->emit('setEdit', false);
         } catch (\Exception $ex) {
-            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+            session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
         }
     }
 
-    public function edit($id){
+    public function edit($id)
+    {
         if (!isset($_GET["from"]) && $this->fromPage == '')
             $this->fromPage = 'out';
         $this->emit('setEdit', true);
         $this->emit('load-select');
         //if ($this->hasFilter)
-            $this->emit('hide-search');
+        $this->emit('hide-search');
         try {
             $record = \App\Models\Record::findOrFail($id);
-            if( !$record) {
-                session()->flash('error','Movimento non trovato');
+            if (!$record) {
+                session()->flash('error', 'Movimento non trovato');
             } else {
                 $this->member_id = $record->member_id;
                 $this->supplier_id = $record->supplier_id;
                 //$this->causal_id = $record->causal_id;
                 $this->payment_method_id = $record->payment_method_id;
                 $this->date = date("Y-m-d", strtotime($record->date));
+                $this->data_pagamento = date("Y-m-d", strtotime($record->data_pagamento));
                 //$this->month = $record->month;
                 //$this->year = $record->year;
                 //$this->note = $record->note;
@@ -386,16 +428,34 @@ class RecordOUT extends Component
                 $this->update = true;
                 $this->add = false;
 
-                $this->rows = \App\Models\RecordRow::where('record_id', $this->dataId)->select('causal_id', 'note', 'commercial', 'when', 'amount')->get()->toArray();
-                foreach($this->rows as $i => $r)
-                {
-                    $this->rows[$i]['amount'] = formatPrice($this->rows[$i]['amount']);
-                    $this->rows[$i]['when'] = json_decode($this->rows[$i]['when']);
-                }
+                $this->rows = [];
 
+                $recordRows = \App\Models\RecordRow::where('record_id', $this->dataId)->get();
+
+                foreach ($recordRows as $recordRow) {
+                    $rowData = [
+                        'causal_id' => $recordRow->causal_id,
+                        'note' => $recordRow->note,
+                        'commercial' => $recordRow->commercial,
+                        'when' => json_decode($recordRow->when),
+                        'amount' => formatPrice($recordRow->amount)
+                    ];
+
+                    // Add imponibile field if available in the database
+                    if (isset($recordRow->imponibile)) {
+                        $rowData['imponibile'] = formatPrice($recordRow->imponibile);
+                    }
+
+                    // Add aliquota_iva field if available in the database
+                    if (isset($recordRow->aliquota_iva)) {
+                        $rowData['aliquota_iva'] = $recordRow->aliquota_iva . '%';
+                    }
+
+                    $this->rows[] = $rowData;
+                }
             }
         } catch (\Exception $ex) {
-            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+            session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
         }
     }
 
@@ -403,40 +463,79 @@ class RecordOUT extends Component
     {
         $this->emit('refresh');
         $this->validate();
+        Log::info("Rows: pipo" );
+
         try {
             \App\Models\Record::whereId($this->dataId)->update([
                 'member_id' => $this->member_id,
                 'supplier_id' => $this->supplier_id,
-                //'causal_id' => $this->causal_id,
                 'payment_method_id' => $this->payment_method_id,
                 'date' => $this->date,
-                //'month' => $this->month,
-                //'year' => $this->year,
-                //'note' => $this->note,
+                'data_pagamento' => $this->data_pagamento,
                 'type' => $this->type,
-                //'amount' => $this->currencyToDouble($this->amount),
                 'commercial' => $this->commercial,
             ]);
 
             $tot = 0;
 
-            // Elimino le righe
+            $existingRows = \App\Models\RecordRow::where('record_id', $this->dataId)
+            ->select('id', 'quantita', 'numero_linea')
+            ->get()
+            ->keyBy('id')
+            ->toArray();
+
+            // Delete existing rows
             \App\Models\RecordRow::where('record_id', $this->dataId)->delete();
-            // Inserisco le righe
-            foreach($this->rows as $row)
-            {
-                foreach($row["when"] as $x => $y)
-                {
+
+            // Insert updated rows
+            foreach ($this->rows as $row) {
+                foreach ($row["when"] as $x => $y) {
                     $row["when"][$x]['period'] = $row["when"][$x]['month'] . "-" . $row["when"][$x]['year'];
                 }
-                \App\Models\RecordRow::create([
+
+                // Get imponibile and aliquota_iva values if they exist
+                $imponibile = null;
+                if (isset($row["imponibile"]) && $row["imponibile"] !== null && $row["imponibile"] !== '') {
+                    $imponibile = $this->currencyToDouble($row["imponibile"]);
+                    Log::info("Imponibile: " . $imponibile);
+                }
+
+                $aliquota_iva = null;
+                if (isset($row["aliquota_iva"]) && $row["aliquota_iva"] !== null && $row["aliquota_iva"] !== '') {
+                    $aliquota_iva = floatval(str_replace('%', '', $row["aliquota_iva"]));
+                    Log::info("Aliquota IVA: " . $aliquota_iva);
+                }
+
+                $amount = $this->currencyToDouble($row["amount"]);
+
+                // Calculate imposta (amount - imponibile) if imponibile exists
+                $imposta = null;
+                if ($imponibile !== null) {
+                    $imposta = $amount - $imponibile;
+                    Log::info("Imposta calculated: " . $imposta);
+                }
+
+                $recordRowData = [
                     'record_id' => $this->dataId,
                     'causal_id' => $row["causal_id"],
                     'note' => $row["note"],
                     'amount' => $this->currencyToDouble($row["amount"]),
                     'commercial' => $row["commercial"],
-                    'when' => json_encode($row["when"])
-                ]);
+                    'when' => json_encode($row["when"]),
+                    'imponibile' => $imponibile,
+                    'aliquota_iva' => $aliquota_iva,
+                    'imposta' => $imposta,
+                    'divisa' => 'EUR', // Assuming the currency is always EUR
+                ];
+
+                if (isset($row["id"]) && isset($existingRows[$row["id"]])) {
+                    $existingRow = $existingRows[$row["id"]];
+                    $recordRowData['quantita'] = $existingRow['quantita'];
+                    $recordRowData['numero_linea'] = $existingRow['numero_linea'];
+                }
+
+                Log::info("RecordRowData: " . json_encode($recordRowData));
+                \App\Models\RecordRow::create($recordRowData);
                 $tot += $this->currencyToDouble($row["amount"]);
             }
 
@@ -444,12 +543,12 @@ class RecordOUT extends Component
             $rec->amount = $tot;
             $rec->save();
 
-            session()->flash('success','Movimento aggiornato');
+            session()->flash('success', 'Movimento aggiornato');
             $this->resetFields();
             $this->update = false;
             $this->emit('setEdit', false);
         } catch (\Exception $ex) {
-            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+            session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
         }
     }
 
@@ -463,23 +562,22 @@ class RecordOUT extends Component
 
     public function delete($id)
     {
-        try{
+        try {
             \App\Models\Record::find($id)->delete();
-            session()->flash('success',"Movimento eliminato");
-        }catch(\Exception $e){
-            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+            session()->flash('success', "Movimento eliminato");
+        } catch (\Exception $e) {
+            session()->flash('error', 'Errore (' . $e->getMessage() . ')');
         }
     }
 
     public function multipleDelete()
     {
-        try{
-            foreach($this->multipleIds as $id)
-            {
+        try {
+            foreach ($this->multipleIds as $id) {
                 \App\Models\Record::find($id)->delete();
             }
-        }catch(\Exception $e){
-            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+        } catch (\Exception $e) {
+            session()->flash('error', 'Errore (' . $e->getMessage() . ')');
         }
         $this->multipleAction = '';
     }
@@ -553,7 +651,15 @@ class RecordOUT extends Component
 
     public function addRow()
     {
-        $this->rows[] = array('causal_id' => null, 'when' => array(array('month' => date("n"), 'year' => date("Y"), 'period' => '')),  'amount' => null, 'note' => '', 'commercial' => 0);
+        $this->rows[] = array(
+            'causal_id' => null,
+            'when' => array(array('month' => date("n"), 'year' => date("Y"), 'period' => '')),
+            'amount' => null,
+            'imponibile' => null,
+            'aliquota_iva' => null,
+            'note' => '',
+            'commercial' => 0
+        );
         $this->emit('load-select');
     }
 
@@ -580,8 +686,7 @@ class RecordOUT extends Component
     public function getTotal()
     {
         $total = 0.00;
-        foreach($this->rows as $r)
-        {
+        foreach ($this->rows as $r) {
             $total += $this->currencyToDouble($r["amount"] != null ? $r["amount"] : 0);
         }
         return formatPrice($total);
@@ -609,7 +714,6 @@ class RecordOUT extends Component
         }
 
         $this->multiP = false;
-
     }
 
     public function multiPeriodCancel()
@@ -617,4 +721,720 @@ class RecordOUT extends Component
         $this->multiP = false;
     }
 
+
+
+    public function importReceipts()
+    {
+        $this->validate([
+            'receiptFiles.*' => 'required|mimes:xml|max:2048',
+            'selectedCausal' => 'required|exists:causals,id',
+        ]);
+
+        try {
+            $importCount = 0;
+            $errorsCount = 0;
+            $totalFiles = count($this->receiptFiles);
+
+            // disabilita select
+            $this->emit('import-started');
+
+            foreach ($this->receiptFiles as $index => $receiptFile) {
+                try {
+                    // Carica e analizza il file XML
+                    $xmlString = file_get_contents($receiptFile->getRealPath());
+                    $xml = simplexml_load_string($xmlString);
+
+                    if (!$xml) {
+                        throw new \Exception("Impossibile analizzare il file XML");
+                    }
+
+                    // Estrai i dati dalla fattura elettronica
+                    $fatturaData = $this->extractFatturaData($xml);
+
+                    // Trova o crea il fornitore
+                    $supplier = $this->findOrCreateSupplier($fatturaData);
+
+                    // Trova il metodo di pagamento
+                    $paymentMethodId = $this->findPaymentMethod($fatturaData['modalitaPagamento']);
+
+                    // Crea il record principale
+                    $record = $this->createRecord($supplier->id, $paymentMethodId, $fatturaData);
+
+                    // Crea il record row
+                    $this->createRecordRow($record->id, $fatturaData);
+
+                    // Crea la ricevuta
+                    //$receipt = $this->createReceipt($record->id, $supplier->id, $paymentMethodId, $fatturaData);
+
+                    // Crea le righe della ricevuta
+                    // $this->createReceiptRows($receipt->id, $fatturaData);
+
+                    $importCount++;
+                    Log::info("Fattura importata con successo: {$fatturaData['numeroFattura']}, Fornitore: {$fatturaData['denominazione']}");
+                } catch (\Exception $e) {
+                    Log::error('Errore durante l\'importazione della fattura: ' . $e->getMessage());
+                    $errorsCount++;
+                }
+
+                $progress = ($index + 1) / $totalFiles * 100;
+                $this->emit('update-progress', $progress);
+            }
+
+            $this->showResultMessages($importCount, $errorsCount);
+        } catch (\Exception $e) {
+            Log::error('Errore durante l\'importazione dei file XML: ' . $e->getMessage());
+            session()->flash('error', 'Errore durante l\'importazione: ' . $e->getMessage());
+        } finally {
+            $this->emit('import-finished');
+
+            $this->closeImportModal();
+            $this->emit('load-data-table');
+        }
+    }
+    /**
+     * Estrae i dati dalla fattura elettronica XML
+     */
+    private function extractFatturaData($xml)
+    {
+        $data = [];
+
+        try {
+            // Stampa la struttura XML per debug
+            Log::info("Nomi dei children dell'elemento radice: " . implode(", ", array_map(function ($node) {
+                return $node->getName();
+            }, iterator_to_array($xml->children()))));
+
+            $headerNode = $xml->FatturaElettronicaHeader;
+            $bodyNode = $xml->FatturaElettronicaBody;
+
+            if (!$headerNode || !$bodyNode) {
+                throw new \Exception("Struttura XML non standard, FatturaElettronicaHeader o FatturaElettronicaBody non trovati");
+            }
+
+            // Estrai dati del fornitore (cedente/prestatore)
+            $cedenteNode = $headerNode->CedentePrestatore;
+            $datiAnagrafici = $cedenteNode->DatiAnagrafici;
+            $idFiscaleIVA = $datiAnagrafici->IdFiscaleIVA;
+
+            $data['idPaese'] = (string)$idFiscaleIVA->IdPaese;
+            $data['idCodice'] = (string)$idFiscaleIVA->IdCodice;
+            $data['partitaIva'] = $data['idPaese'] . $data['idCodice'];
+            $data['codiceFiscale'] = (string)$datiAnagrafici->CodiceFiscale;
+            $data['denominazione'] = (string)$datiAnagrafici->Anagrafica->Denominazione;
+
+            // Estrai dati della sede
+            $sede = $cedenteNode->Sede;
+            $data['indirizzo'] = (string)$sede->Indirizzo;
+            $data['cap'] = (string)$sede->CAP;
+            $data['comune'] = (string)$sede->Comune;
+            $data['provincia'] = (string)$sede->Provincia;
+            $data['nazione'] = (string)$sede->Nazione ?: 'IT';
+
+            // Email, se presente
+            $data['email'] = '';
+            if (isset($cedenteNode->Contatti) && isset($cedenteNode->Contatti->Email)) {
+                $data['email'] = (string)$cedenteNode->Contatti->Email;
+            }
+
+            // Dati generali della fattura
+            $datiGeneraliDocumento = $bodyNode->DatiGenerali->DatiGeneraliDocumento;
+            $data['tipoDocumento'] = (string)$datiGeneraliDocumento->TipoDocumento;
+            $data['divisa'] = (string)$datiGeneraliDocumento->Divisa ?: 'EUR';
+            $data['dataDocumento'] = (string)$datiGeneraliDocumento->Data;
+            $data['numeroFattura'] = (string)$datiGeneraliDocumento->Numero;
+            $data['importoTotale'] = (float)$datiGeneraliDocumento->ImportoTotaleDocumento;
+
+            // Dati di pagamento
+            $data['condizioniPagamento'] = '';
+            $data['modalitaPagamento'] = '';
+            $data['dataScadenza'] = '';
+            $data['iban'] = '';
+            $data['bic'] = '';
+            $data['istitutoFinanziario'] = '';
+
+            if (isset($bodyNode->DatiPagamento)) {
+                $datiPagamento = $bodyNode->DatiPagamento;
+                $data['condizioniPagamento'] = (string)$datiPagamento->CondizioniPagamento;
+
+                if (isset($datiPagamento->DettaglioPagamento)) {
+                    $dettaglioPagamento = $datiPagamento->DettaglioPagamento;
+                    $data['modalitaPagamento'] = (string)$dettaglioPagamento->ModalitaPagamento;
+                    $data['dataScadenza'] = (string)$dettaglioPagamento->DataScadenzaPagamento;
+                    $data['iban'] = (string)$dettaglioPagamento->IBAN;
+                    $data['bic'] = (string)$dettaglioPagamento->BIC;
+                    $data['istitutoFinanziario'] = (string)$dettaglioPagamento->IstitutoFinanziario;
+                }
+            }
+
+            // Estrai le linee di dettaglio
+            $data['linee'] = [];
+            if (isset($bodyNode->DatiBeniServizi) && isset($bodyNode->DatiBeniServizi->DettaglioLinee)) {
+                foreach ($bodyNode->DatiBeniServizi->DettaglioLinee as $index => $linea) {
+                    $lineaData = [
+                        'numeroLinea' => (int)($linea->NumeroLinea ?? ($index + 1)),
+                        'descrizione' => (string)($linea->Descrizione ?? ''),
+                        'quantita' => (float)($linea->Quantita ?? 1),
+                        'prezzoUnitario' => (float)($linea->PrezzoUnitario ?? 0),
+                        'prezzoTotale' => (float)($linea->PrezzoTotale ?? 0),
+                        'aliquotaIva' => (float)($linea->AliquotaIVA ?? 0),
+                    ];
+
+                    // Calcola il prezzo totale se non presente
+                    if ($lineaData['prezzoTotale'] == 0) {
+                        $lineaData['prezzoTotale'] = $lineaData['quantita'] * $lineaData['prezzoUnitario'];
+                    }
+
+                    $data['linee'][] = $lineaData;
+                }
+            }
+
+            $data['riepilogo'] = null;
+            if (isset($bodyNode->DatiBeniServizi) && isset($bodyNode->DatiBeniServizi->DatiRiepilogo)) {
+                $riepilogoNode = $bodyNode->DatiBeniServizi->DatiRiepilogo;
+                if ($riepilogoNode) {
+                    $data['riepilogo'] = [
+                        'aliquotaIva' => (float)($riepilogoNode->AliquotaIVA ?? 0),
+                        'imponibile' => (float)($riepilogoNode->ImponibileImporto ?? 0),
+                        'imposta' => (float)($riepilogoNode->Imposta ?? 0),
+                    ];
+                }
+            }
+
+            Log::info("Dati estratti dalla fattura: P.IVA={$data['partitaIva']}, Denominazione={$data['denominazione']}, Numero={$data['numeroFattura']}, Importo={$data['importoTotale']}");
+
+            return $data;
+        } catch (\Exception $e) {
+            Log::error("Errore nell'estrazione dei dati XML: " . $e->getMessage());
+            throw $e;
+        }
+    }
+
+
+    /**
+     * Trova o crea un fornitore basato sui dati della fattura
+     */
+    private function findOrCreateSupplier($fatturaData)
+    {
+        $supplier = \App\Models\Supplier::where('vat', $fatturaData['partitaIva'])->first();
+
+        if (!$supplier) {
+            Log::info("Creazione nuovo fornitore con P.IVA: {$fatturaData['partitaIva']} ({$fatturaData['denominazione']})");
+
+            $countryId = $this->getCountryId($fatturaData['nazione']);
+            $provinceId = $this->getProvinceId($fatturaData['provincia']);
+            $cityId = $this->getCityId($fatturaData['comune']);
+
+            $supplier = new \App\Models\Supplier();
+            $supplier->name = $fatturaData['denominazione'];
+            $supplier->vat = $fatturaData['partitaIva'];
+            $supplier->fiscal_code = $fatturaData['codiceFiscale'];
+            $supplier->address = $fatturaData['indirizzo'];
+            $supplier->city_id = $cityId;
+            $supplier->zip_code = $fatturaData['cap'];
+            $supplier->province_id = $provinceId;
+            $supplier->nation_id = $countryId;
+            $supplier->email = $fatturaData['email'];
+            $supplier->save();
+
+            Log::info("Fornitore creato con ID: " . $supplier->id);
+        }
+
+        return $supplier;
+    }
+
+    /**
+     * Trova l'ID della nazione dal codice
+     */
+    private function getCountryId($nationCode)
+    {
+        $country = DB::table('nations')->where('code', $nationCode)->first();
+        return $country ? $country->id : null;
+    }
+
+    /**
+     * Trova l'ID della provincia dal codice
+     */
+    private function getProvinceId($provinceCode)
+    {
+        $province = DB::table('provinces')->where('code', $provinceCode)->first();
+        return $province ? $province->id : null;
+    }
+
+    /**
+     * Trova l'ID della città dal nome
+     */
+    private function getCityId($cityName)
+    {
+        if (empty($cityName)) return null;
+
+        $city = DB::table('cities')->where('name', $cityName)->first();
+        return $city ? $city->id : null;
+    }
+
+    /**
+     * Trova l'ID del metodo di pagamento dal codice
+     */
+    private function findPaymentMethod($paymentCode)
+    {
+        if (!empty($paymentCode)) {
+            $paymentMethod = DB::table('payment_methods')->where('code', $paymentCode)->first();
+            if ($paymentMethod) {
+                Log::info("Metodo di pagamento trovato: $paymentCode (ID: {$paymentMethod->id})");
+                return $paymentMethod->id;
+            }
+        }
+
+        $defaultPaymentMethod = DB::table('payment_methods')->where('default', 1)->first()
+            ?? DB::table('payment_methods')->first();
+
+        if ($defaultPaymentMethod) {
+            Log::info("Usando metodo di pagamento predefinito ID: {$defaultPaymentMethod->id}");
+            return $defaultPaymentMethod->id;
+        }
+
+        throw new \Exception("Nessun metodo di pagamento disponibile nel sistema");
+    }
+    /**
+     * Crea un record nella tabella records
+     */
+    private function createRecord($supplierId, $paymentMethodId, $fatturaData)
+    {
+        $record = new \App\Models\Record();
+        $record->supplier_id = $supplierId;
+        $record->payment_method_id = $paymentMethodId;
+        $record->date = $fatturaData['dataDocumento'];
+        $record->data_pagamento = $fatturaData['dataDocumento'];
+        $record->numero_fattura =  $fatturaData['numeroFattura'];
+        $record->type = 'OUT';
+        $record->commercial = 1;
+        $record->corrispettivo_fiscale = 0;
+        $record->deleted = 0;
+        $record->financial_movement = 1;
+        $record->amount = $fatturaData['importoTotale'];
+        $record->tipo_documento = $this->mapTipoDocumento($fatturaData['tipoDocumento']);
+
+        $record->is_ricevuta = true;
+        if (isset($fatturaData['condizioniPagamento']) && !empty($fatturaData['condizioniPagamento'])) {
+            $record->condizioni_pagamento = $this->mapCondizioniPagamento($fatturaData['condizioniPagamento']);
+        }
+        if (isset($fatturaData['iban']) && !empty($fatturaData['iban'])) {
+            $record->IBAN = $fatturaData['iban'];
+        }
+        if (isset($fatturaData['bic']) && !empty($fatturaData['bic'])) {
+            $record->BIC = $fatturaData['bic'];
+        }
+        if (isset($fatturaData['dataScadenza']) && !empty($fatturaData['dataScadenza'])) {
+            $record->data_scadenza = $fatturaData['dataScadenza'];
+        }
+        $record->save();
+
+        Log::info("Record creato con ID: " . $record->id);
+
+        return $record;
+    }
+
+    /**
+     * Crea un record row per il record specificato
+     */
+    private function createRecordRow($recordId, $fatturaData)
+    {
+        Log::info("Inizio creazione RecordRow per Record ID: " . $recordId);
+
+        if (!empty($fatturaData['linee'])) {
+            foreach ($fatturaData['linee'] as $linea) {
+                $this->createSingleRecordRow($recordId, $fatturaData, $linea);
+            }
+        } else if ($fatturaData['riepilogo']) {
+            $this->createRecordRowFromRiepilogo($recordId, $fatturaData);
+            Log::info("Creata una riga di record dai dati di riepilogo");
+        } else {
+            $this->createDefaultRecordRow($recordId, $fatturaData);
+            Log::info("Creata una riga di record predefinita dall'importo totale");
+        }
+    }
+
+    private function createSingleRecordRow($recordId, $fatturaData, $linea)
+    {
+        Log::info("Inizio creazione riga record singola per Record ID: " . $recordId . ", Linea: " . json_encode($linea));
+
+        $dataObj = new \DateTime($fatturaData['dataDocumento']);
+        $month = $dataObj->format('n');
+        $year = $dataObj->format('Y');
+        $period = "$month-$year";
+
+        $whenData = [[
+            'month' => $month,
+            'year' => $year,
+            'period' => $period
+        ]];
+
+        $recordRow = new \App\Models\RecordRow();
+        $recordRow->record_id = $recordId;
+        $recordRow->causal_id = $this->selectedCausal;
+        $recordRow->amount = $linea['prezzoTotale'] + $linea['prezzoTotale'] * ($linea['aliquotaIva'] / 100);
+        $recordRow->note = $linea['descrizione'];
+        $recordRow->commercial = 1;
+
+        $recordRow->when = json_encode($whenData);
+        $recordRow->aliquota_iva = $linea['aliquotaIva'];
+        $recordRow->imponibile = $linea['prezzoTotale'];
+        $recordRow->imposta = $linea['prezzoTotale'] * ($linea['aliquotaIva'] / 100);
+        $recordRow->divisa = $fatturaData['divisa'];
+        $recordRow->numero_linea = $linea['numeroLinea'];
+        $recordRow->prezzo_unitario = $linea['prezzoUnitario'];
+        $recordRow->quantita = $linea['quantita'];
+
+        Log::info("Dati riga record prima del salvataggio: " . json_encode([
+            'record_id' => $recordRow->record_id,
+            'causal_id' => $recordRow->causal_id,
+            'amount' => $recordRow->amount,
+            'note' => $recordRow->note,
+            'aliquota_iva' => $recordRow->aliquota_iva,
+            'imponibile' => $recordRow->imponibile,
+            'imposta' => $recordRow->imposta,
+            'divisa' => $recordRow->divisa,
+            'numero_linea' => $recordRow->numero_linea,
+            'prezzo_unitario' => $recordRow->prezzo_unitario,
+            'quantita' => $recordRow->quantita,
+        ]));
+
+        $recordRow->save();
+
+        Log::info("Riga record creata per linea {$linea['numeroLinea']}: {$linea['descrizione']} (€{$linea['prezzoTotale']})");
+    }
+
+    private function createRecordRowFromRiepilogo($recordId, $fatturaData)
+    {
+        Log::info("Inizio creazione riga record da riepilogo per Record ID: " . $recordId . ", Riepilogo: " . json_encode($fatturaData['riepilogo']));
+
+        $riepilogo = $fatturaData['riepilogo'];
+
+        $dataObj = new \DateTime($fatturaData['dataDocumento']);
+        $month = $dataObj->format('n');
+        $year = $dataObj->format('Y');
+        $period = "$month-$year";
+
+        $whenData = [[
+            'month' => $month,
+            'year' => $year,
+            'period' => $period
+        ]];
+        $total_amount = $riepilogo['imponibile'] + $riepilogo['imposta'];
+        $recordRow = new \App\Models\RecordRow();
+        $recordRow->record_id = $recordId;
+        $recordRow->causal_id = $this->selectedCausal;
+        $recordRow->amount = $total_amount;
+        $recordRow->commercial = 1;
+
+        $recordRow->when = json_encode($whenData);
+        $recordRow->aliquota_iva = $riepilogo['aliquotaIva'];
+        $recordRow->imponibile = $riepilogo['imponibile'];
+        $recordRow->imposta = $riepilogo['imposta'];
+        $recordRow->divisa = $fatturaData['divisa'];
+        $recordRow->numero_linea = 1;
+        $recordRow->quantita = 1;
+
+        Log::info("Dati riga record da riepilogo prima del salvataggio: " . json_encode([
+            'record_id' => $recordRow->record_id,
+            'causal_id' => $recordRow->causal_id,
+            'amount' => $recordRow->amount,
+            'aliquota_iva' => $recordRow->aliquota_iva,
+            'imponibile' => $recordRow->imponibile,
+            'imposta' => $recordRow->imposta,
+            'divisa' => $recordRow->divisa,
+        ]));
+
+        $recordRow->save();
+
+        Log::info("Riga record creata da riepilogo: Imponibile={$riepilogo['imponibile']}, IVA={$riepilogo['aliquotaIva']}%");
+    }
+
+    private function createDefaultRecordRow($recordId, $fatturaData)
+    {
+        Log::info("Inizio creazione riga record predefinita per Record ID: " . $recordId . ", Importo Totale: " . $fatturaData['importoTotale']);
+
+        $dataObj = new \DateTime($fatturaData['dataDocumento']);
+        $month = $dataObj->format('n');
+        $year = $dataObj->format('Y');
+        $period = "$month-$year";
+
+        $whenData = [[
+            'month' => $month,
+            'year' => $year,
+            'period' => $period
+        ]];
+        $recordRow = new \App\Models\RecordRow();
+        $recordRow->record_id = $recordId;
+        $recordRow->causal_id = $this->selectedCausal;
+        $recordRow->amount = $fatturaData['importoTotale'];
+        $recordRow->commercial = 1;
+
+
+        $recordRow->when = json_encode($whenData);
+        $recordRow->divisa = $fatturaData['divisa'];
+        $recordRow->numero_linea = 1;
+        $recordRow->quantita = 1;
+
+        Log::info("Dati riga record predefinita prima del salvataggio: " . json_encode([
+            'record_id' => $recordRow->record_id,
+            'causal_id' => $recordRow->causal_id,
+            'amount' => $recordRow->amount,
+            'divisa' => $recordRow->divisa,
+        ]));
+
+        $recordRow->save();
+
+        Log::info("Riga record predefinita creata con importo totale: {$fatturaData['importoTotale']}");
+    }
+    /**
+     * Crea una ricevuta collegata al record
+     */
+    /* private function createReceipt($recordId, $supplierId, $paymentMethodId, $fatturaData)
+    {
+        Log::info("Inizio creazione ricevuta per Record ID: " . $recordId);
+
+        $receipt = new \App\Models\Receipt();
+        $receipt->record_id = $recordId;
+        $receipt->supplier_id = $supplierId;
+        $receipt->payment_method_id = $paymentMethodId;
+        $receipt->date = $fatturaData['dataDocumento'];
+        $receipt->data_pagamento = $fatturaData['dataDocumento'];
+        $receipt->numero_fattura =  $fatturaData['numeroFattura'];
+        $receipt->number = preg_replace('/[^0-9]/', '', $fatturaData['numeroFattura']);
+        $receipt->tipo_documento = $this->mapTipoDocumento($fatturaData['tipoDocumento']);
+        $receipt->year = date('Y', strtotime($fatturaData['dataDocumento']));
+        $receipt->type = 'OUT';
+        $receipt->status = 1;
+        $receipt->is_ricevuta = true;
+        if (isset($fatturaData['condizioniPagamento']) && !empty($fatturaData['condizioniPagamento'])) {
+            $receipt->condizioni_pagamento = $this->mapCondizioniPagamento($fatturaData['condizioniPagamento']);
+        }
+        if (isset($fatturaData['iban']) && !empty($fatturaData['iban'])) {
+            $receipt->IBAN = $fatturaData['iban'];
+        }
+        if (isset($fatturaData['bic']) && !empty($fatturaData['bic'])) {
+            $receipt->BIC = $fatturaData['bic'];
+        }
+        if (isset($fatturaData['dataScadenza']) && !empty($fatturaData['dataScadenza'])) {
+            $receipt->data_scadenza = $fatturaData['dataScadenza'];
+        }
+
+        Log::info("Dati ricevuta prima del salvataggio: " . json_encode([
+            'record_id' => $receipt->record_id,
+            'supplier_id' => $receipt->supplier_id,
+            'payment_method_id' => $receipt->payment_method_id,
+            'date' => $receipt->date,
+            'number' => $receipt->number,
+            'tipo_documento' => $receipt->tipo_documento,
+            'year' => $receipt->year,
+            'type' => $receipt->type,
+            'status' => $receipt->status,
+        ]));
+
+        $receipt->save();
+
+        Log::info("Ricevuta creata con ID: " . $receipt->id);
+
+        return $receipt;
+    }
+
+    private function createReceiptRows($receiptId, $fatturaData)
+    {
+        Log::info("Inizio creazione righe ricevuta per Ricevuta ID: " . $receiptId);
+
+        if (!empty($fatturaData['linee'])) {
+            foreach ($fatturaData['linee'] as $linea) {
+                $this->createSingleReceiptRow($receiptId, $fatturaData, $linea);
+            }
+        } else if ($fatturaData['riepilogo']) {
+            $this->createReceiptRowFromRiepilogo($receiptId, $fatturaData);
+            Log::info("Creata una riga di ricevuta dai dati di riepilogo");
+        } else {
+            $this->createDefaultReceiptRow($receiptId, $fatturaData);
+            Log::info("Creata una riga di ricevuta predefinita dall'importo totale");
+        }
+    }
+
+    private function createSingleReceiptRow($receiptId, $fatturaData, $linea)
+    {
+        Log::info("Inizio creazione riga ricevuta singola per Ricevuta ID: " . $receiptId . ", Linea: " . json_encode($linea));
+
+        $dataObj = new \DateTime($fatturaData['dataDocumento']);
+        $month = $dataObj->format('n');
+        $year = $dataObj->format('Y');
+        $period = "$month-$year";
+
+        $whenData = [[
+            'month' => $month,
+            'year' => $year,
+            'period' => $period
+        ]];
+
+        $receiptRow = new \App\Models\ReceiptRow();
+        $receiptRow->receip_id = $receiptId;
+        $receiptRow->causal_id = $this->selectedCausal;
+        $receiptRow->amount = $linea['prezzoTotale'] + $linea['prezzoTotale'] * ($linea['aliquotaIva'] / 100);
+        $receiptRow->note = $linea['descrizione'];
+        $receiptRow->commercial = 1;
+
+        $receiptRow->when = json_encode($whenData);
+        $receiptRow->aliquota_iva = $linea['aliquotaIva'];
+        $receiptRow->imponibile = $linea['prezzoTotale'];
+        $receiptRow->imposta = $linea['prezzoTotale'] * ($linea['aliquotaIva'] / 100);
+        $receiptRow->divisa = $fatturaData['divisa'];
+        $receiptRow->numero_linea = $linea['numeroLinea'];
+        $receiptRow->prezzo_unitario = $linea['prezzoUnitario'];
+        $receiptRow->quantita = $linea['quantita'];
+
+        Log::info("Dati riga ricevuta prima del salvataggio: " . json_encode([
+            'receip_id' => $receiptRow->receip_id,
+            'causal_id' => $receiptRow->causal_id,
+            'amount' => $receiptRow->amount,
+            'note' => $receiptRow->note,
+            'aliquota_iva' => $receiptRow->aliquota_iva,
+            'imponibile' => $receiptRow->imponibile,
+            'imposta' => $receiptRow->imposta,
+            'divisa' => $receiptRow->divisa,
+            'numero_linea' => $receiptRow->numero_linea,
+            'prezzo_unitario' => $receiptRow->prezzo_unitario,
+            'quantita' => $receiptRow->quantita,
+        ]));
+
+        $receiptRow->save();
+
+        Log::info("Riga ricevuta creata per linea {$linea['numeroLinea']}: {$linea['descrizione']} (€{$linea['prezzoTotale']})");
+    }
+
+    private function createReceiptRowFromRiepilogo($receiptId, $fatturaData)
+    {
+        Log::info("Inizio creazione riga ricevuta da riepilogo per Ricevuta ID: " . $receiptId . ", Riepilogo: " . json_encode($fatturaData['riepilogo']));
+
+        $riepilogo = $fatturaData['riepilogo'];
+
+        $dataObj = new \DateTime($fatturaData['dataDocumento']);
+        $month = $dataObj->format('n');
+        $year = $dataObj->format('Y');
+        $period = "$month-$year";
+
+        $whenData = [[
+            'month' => $month,
+            'year' => $year,
+            'period' => $period
+        ]];
+        $total_amount = $riepilogo['imponibile'] + $riepilogo['imposta'];
+        $receiptRow = new \App\Models\ReceiptRow();
+        $receiptRow->receip_id = $receiptId;
+        $receiptRow->causal_id = $this->selectedCausal;
+        $receiptRow->amount = $total_amount;
+        $receiptRow->commercial = 1;
+
+        $receiptRow->when = json_encode($whenData);
+        $receiptRow->aliquota_iva = $riepilogo['aliquotaIva'];
+        $receiptRow->imponibile = $riepilogo['imponibile'];
+        $receiptRow->imposta = $riepilogo['imposta'];
+        $receiptRow->divisa = $fatturaData['divisa'];
+        $receiptRow->numero_linea = 1;
+        $receiptRow->quantita = 1;
+
+        Log::info("Dati riga ricevuta da riepilogo prima del salvataggio: " . json_encode([
+            'receip_id' => $receiptRow->receip_id,
+            'causal_id' => $receiptRow->causal_id,
+            'amount' => $receiptRow->amount,
+            'aliquota_iva' => $receiptRow->aliquota_iva,
+            'imponibile' => $receiptRow->imponibile,
+            'imposta' => $receiptRow->imposta,
+            'divisa' => $receiptRow->divisa,
+        ]));
+
+        $receiptRow->save();
+
+        Log::info("Riga ricevuta creata da riepilogo: Imponibile={$riepilogo['imponibile']}, IVA={$riepilogo['aliquotaIva']}%");
+    }
+
+    private function createDefaultReceiptRow($receiptId, $fatturaData)
+    {
+        Log::info("Inizio creazione riga ricevuta predefinita per Ricevuta ID: " . $receiptId . ", Importo Totale: " . $fatturaData['importoTotale']);
+
+        $dataObj = new \DateTime($fatturaData['dataDocumento']);
+        $month = $dataObj->format('n');
+        $year = $dataObj->format('Y');
+        $period = "$month-$year";
+
+        $whenData = [[
+            'month' => $month,
+            'year' => $year,
+            'period' => $period
+        ]];
+        $receiptRow = new \App\Models\ReceiptRow();
+        $receiptRow->receip_id = $receiptId;
+        $receiptRow->causal_id = $this->selectedCausal;
+        $receiptRow->amount = $fatturaData['importoTotale'];
+        $receiptRow->commercial = 1;
+
+        $receiptRow->when = json_encode($whenData);
+        $receiptRow->divisa = $fatturaData['divisa'];
+        $receiptRow->numero_linea = 1;
+        $receiptRow->quantita = 1;
+
+        Log::info("Dati riga ricevuta predefinita prima del salvataggio: " . json_encode([
+            'receip_id' => $receiptRow->receip_id,
+            'causal_id' => $receiptRow->causal_id,
+            'amount' => $receiptRow->amount,
+            'divisa' => $receiptRow->divisa,
+        ]));
+
+        $receiptRow->save();
+
+        Log::info("Riga ricevuta predefinita creata con importo totale: {$fatturaData['importoTotale']}");
+    }
+ */
+    private function mapTipoDocumento($codice)
+    {
+        $tipiDocumento = [
+            'TD01' => 'Fattura',
+            'TD02' => 'Acconto/Anticipo su fattura',
+            'TD03' => 'Acconto/Anticipo su parcella',
+            'TD04' => 'Nota di credito',
+            'TD05' => 'Nota di debito',
+            'TD06' => 'Parcella',
+            'TD16' => 'Integrazione fattura reverse charge interno',
+            'TD17' => 'Integrazione/autofattura per acquisto servizi dall\'estero',
+            'TD18' => 'Integrazione per acquisto di beni intracomunitari',
+            'TD19' => 'Integrazione/autofattura per acquisto di beni ex art.17 c.2 DPR 633/72',
+            'TD20' => 'Autofattura per regolarizzazione e integrazione delle fatture',
+            'TD21' => 'Autofattura per splafonamento',
+            'TD22' => 'Estrazione beni da Deposito IVA',
+            'TD23' => 'Estrazione beni da Deposito IVA con versamento dell\'IVA',
+            'TD24' => 'Fattura differita di cui all\'art.21, comma 4, lett. a)',
+            'TD25' => 'Fattura differita di cui all\'art.21, comma 4, terzo periodo lett. b)',
+            'TD26' => 'Cessione di beni ammortizzabili e per passaggi interni',
+            'TD27' => 'Fattura per autoconsumo o per cessioni gratuite senza rivalsa'
+        ];
+
+        return $tipiDocumento[$codice] ?? $codice;
+    }
+
+    private function mapCondizioniPagamento($codice)
+    {
+        $condizioniPagamento = [
+            'TP01' => 'Pagamento a rate',
+            'TP02' => 'Pagamento completo',
+            'TP03' => 'Anticipo'
+        ];
+
+        return $condizioniPagamento[$codice] ?? $codice;
+    }
+
+    private function showResultMessages($importCount, $errorsCount)
+    {
+        if ($importCount > 0) {
+            $message = "Importate $importCount fatture con successo.";
+            if ($errorsCount > 0) {
+                $message .= " $errorsCount fatture non sono state importate.";
+            }
+            session()->flash('message', $message);
+        } else {
+            session()->flash('error', 'Nessuna fattura importata. Controlla i file XML e riprova.');
+        }
+    }
 }

+ 74 - 0
app/Models/Azienda.php

@@ -0,0 +1,74 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class Azienda extends Model
+{
+    use HasFactory;
+
+    protected $fillable = [
+        'ragione_sociale',
+        'nome_associazione',
+        'tipologia',
+        'logo',
+
+        'sede_legale_nazione',
+        'sede_legale_provincia',
+        'sede_legale_comune',
+        'sede_legale_indirizzo',
+        'sede_legale_cap',
+
+        'sede_operativa_nazione',
+        'sede_operativa_provincia',
+        'sede_operativa_comune',
+        'sede_operativa_indirizzo',
+        'sede_operativa_cap',
+
+        'email',
+        'pec',
+        'telefono',
+        'cellulare',
+
+        'partita_iva',
+        'codice_fiscale',
+        'codice_sdi',
+
+        'chiusura_anno_fiscale',
+        'scadenza_abbonamenti',
+        'scadenza_pagamenti_uscita',
+    ];
+
+    protected $casts = [
+        'chiusura_anno_fiscale' => 'date',
+        'scadenza_abbonamenti' => 'date',
+        'scadenza_pagamenti_uscita' => 'date',
+    ];
+
+
+    /**
+     * Get the logo URL attribute.
+     *
+     * @return string|null
+     */
+    public function getLogoUrlAttribute()
+    {
+        if ($this->logo) {
+            return asset('storage/' . $this->logo);
+        }
+
+        return null;
+    }
+
+    /**
+     * Get a formatted list of discipline names.
+     *
+     * @return string
+     */
+    public function getDisciplineListAttribute()
+    {
+        return $this->disciplines->pluck('name')->implode(', ');
+    }
+}

+ 12 - 0
app/Models/Discipline.php

@@ -12,8 +12,20 @@ class Discipline extends Model
     protected $fillable = [
         'name',
         'enabled',
+        'code',
+        'sport'
     ];
 
+    public function scopeOfSport($query, $sport)
+    {
+        return $query->where('sport', $sport);
+    }
+
+    public function getFullNameAttribute()
+    {
+        return "{$this->sport} - {$this->name} ({$this->code})";
+    }
+
     public function canDelete()
     {
         return true;

+ 20 - 1
app/Models/ReceiptRow.php

@@ -18,6 +18,22 @@ class ReceiptRow extends Model
         'amount',
         'note',
         'commercial',
+        'aliquota_iva',
+        'imponibile',
+        'imposta',
+        'divisa',
+        'numero_linea',
+        'prezzo_unitario',
+        'quantita'
+    ];
+
+    protected $casts = [
+        'when' => 'json',
+        'aliquota_iva' => 'decimal:2',
+        'imponibile' => 'decimal:2',
+        'imposta' => 'decimal:2',
+        'prezzo_unitario' => 'decimal:2',
+        'quantita' => 'decimal:2',
     ];
 
     public function causal()
@@ -25,5 +41,8 @@ class ReceiptRow extends Model
         return $this->belongsTo(Causal::class);
     }
 
+    public function receipt()
+    {
+        return $this->belongsTo(Receipt::class, 'receip_id', 'id');
+    }
 }
-

+ 6 - 0
app/Models/RecordRow.php

@@ -19,6 +19,12 @@ class RecordRow extends Model
         'vat_id',
         'note',
         'commercial',
+        'aliquota_iva',
+        'imponibile',
+        'imposta',
+        'divisa',
+        'quantita',
+        'numero_linea'
     ];
 
     public function causal()

+ 39 - 0
database/migrations/2025_04_04_101800_add_fields_discipline_table.php

@@ -0,0 +1,39 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('disciplines', function (Blueprint $table) {
+            if (!Schema::hasColumn('disciplines', 'code')) {
+                $table->string('code')->nullable()->after('id');
+
+            }
+
+            if (!Schema::hasColumn('disciplines', 'sport')) {
+                $table->string('sport')->nullable()->after('code');
+            }
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('disciplines', function (Blueprint $table) {
+            $table->dropColumn('code', 'sport');
+        });
+    }
+};

+ 68 - 0
database/migrations/2025_04_04_130150_create_aziendas_table.php

@@ -0,0 +1,68 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('aziendas', function (Blueprint $table) {
+            $table->id();
+
+            // General information
+            $table->string('ragione_sociale');
+            $table->string('nome_associazione')->nullable();
+            $table->string('tipologia')->nullable();
+            $table->string('logo')->nullable();
+
+            // Legal address
+            $table->string('sede_legale_nazione')->nullable();
+            $table->string('sede_legale_provincia')->nullable();
+            $table->string('sede_legale_comune')->nullable();
+            $table->string('sede_legale_indirizzo')->nullable();
+            $table->string('sede_legale_cap')->nullable();
+
+            // Operational address
+            $table->string('sede_operativa_nazione')->nullable();
+            $table->string('sede_operativa_provincia')->nullable();
+            $table->string('sede_operativa_comune')->nullable();
+            $table->string('sede_operativa_indirizzo')->nullable();
+            $table->string('sede_operativa_cap')->nullable();
+
+            // Contacts
+            $table->string('email');
+            $table->string('pec');
+            $table->string('telefono')->nullable();
+            $table->string('cellulare');
+
+            // Fiscal data
+            $table->string('partita_iva')->nullable();
+            $table->string('codice_fiscale')->nullable();
+            $table->string('codice_sdi')->nullable();
+
+            // Accounting configuration
+            $table->date('chiusura_anno_fiscale')->nullable();
+            $table->date('scadenza_abbonamenti')->nullable();
+            $table->date('scadenza_pagamenti_uscita')->nullable();
+
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('aziendas');
+    }
+};

+ 28 - 0
database/migrations/2025_04_04_135831_add_field_discipline_to_aziendas_table.php

@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('aziendas', function (Blueprint $table) {
+            if (Schema::hasColumn('aziendas', 'discipline')) {
+                $table->dropColumn('discipline');
+            }
+
+            $table->text('discipline')->nullable();
+        });
+    }
+    public function down()
+    {
+
+    }
+};

+ 260 - 0
database/migrations/2025_04_07_132625_add_code_to_payment_methods_and_insert_data.php

@@ -0,0 +1,260 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+
+class AddCodeToPaymentMethodsAndInsertData extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        if (!Schema::hasColumn('payment_methods', 'code')) {
+            Schema::table('payment_methods', function (Blueprint $table) {
+                $table->string('code', 10)->nullable()->after('type');
+            });
+        }
+
+        $typeValue = 'ALL';
+
+        $paymentMethods = [
+            [
+                'bank_id' => null,
+                'name' => 'Contanti',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP01'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Assegno',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP02'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Assegno circolare',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP03'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Contanti presso Tesoreria',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP04'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Bonifico',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP05'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Vaglia cambiario',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP06'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Bollettino bancario',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP07'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Carta di credito',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP08'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'RID',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP09'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'RID utenze',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP10'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'RID veloce',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP11'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Riba',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP12'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'MAV',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP13'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Quietanza erario stato',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP14'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Giroconto su conti di contabilità speciale',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP15'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Domiciliazione bancaria',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP16'
+            ],
+            [
+                'bank_id' => null,
+                'name' => 'Domiciliazione postale',
+                'money' => 0,
+                'enabled' => 1,
+                'deleted_at' => null,
+                'created_at' => now(),
+                'updated_at' => now(),
+                'corrispettivo_fiscale' => null,
+                'type' => $typeValue,
+                'code' => 'MP17'
+            ],
+        ];
+
+        foreach ($paymentMethods as $method) {
+            $exists = DB::table('payment_methods')->where('code', $method['code'])->exists();
+
+            if ($exists) {
+                DB::table('payment_methods')
+                    ->where('code', $method['code'])
+                    ->update($method);
+            } else {
+                DB::table('payment_methods')->insert($method);
+            }
+        }
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        if (Schema::hasColumn('payment_methods', 'code')) {
+            Schema::table('payment_methods', function (Blueprint $table) {
+                $table->dropColumn('code');
+            });
+        }
+
+
+    }
+}

+ 46 - 0
database/migrations/2025_04_09_000000_add_fields_to_records_rows_table.php

@@ -0,0 +1,46 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('records_rows', function (Blueprint $table) {
+            $table->decimal('aliquota_iva', 8, 2)->nullable()->after('amount');
+            $table->decimal('imponibile', 8, 2)->nullable()->after('aliquota_iva');
+            $table->decimal('imposta', 8, 2)->nullable()->after('imponibile');
+            $table->string('divisa', 10)->nullable()->after('imposta');
+            $table->integer('numero_linea')->nullable()->after('divisa');
+            $table->decimal('prezzo_unitario', 10, 2)->nullable()->after('numero_linea');
+            $table->decimal('quantita', 10, 2)->nullable()->after('prezzo_unitario');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('records_rows', function (Blueprint $table) {
+            $table->dropColumn([
+                'aliquota_iva',
+                'imponibile',
+                'imposta',
+                'divisa',
+                'numero_linea',
+                'prezzo_unitario',
+                'quantita'
+            ]);
+        });
+    }
+};

+ 55 - 0
database/migrations/2025_04_09_000001_add_fields_and_foreign_key_to_records_table.php

@@ -0,0 +1,55 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('records', function (Blueprint $table) {
+            $table->date('data_pagamento')->nullable()->after('date');
+            $table->string('numero_fattura');
+            $table->string('tipo_documento')->nullable()->after('type');
+            $table->string('BIC')->nullable()->after('tipo_documento');
+            $table->string('IBAN')->nullable()->after('BIC');
+            $table->date('data_scadenza')->nullable()->after('IBAN');
+            $table->unsignedBigInteger('bank_id')->nullable()->after('data_scadenza');
+            $table->string('condizioni_pagamento')->nullable()->after('bank_id');
+            $table->boolean('is_ricevuta')->default(false);
+            $table->foreign('bank_id')
+                  ->references('id')
+                  ->on('banks')
+                  ->onDelete('set null')
+                  ->onUpdate('cascade');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('records', function (Blueprint $table) {
+            $table->dropForeign(['bank_id']);
+
+            $table->dropColumn([
+                'data_documento',
+                'numero_fattura',
+                'tipo_documento',
+                'BIC',
+                'IBAN',
+                'data_scadenza',
+                'bank_id',
+                'condizioni_pagamento'
+            ]);
+        });
+    }
+};

+ 47 - 0
database/migrations/2025_04_09_000002_add_data_pagamento_values_to_records_table.php

@@ -0,0 +1,47 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+return new class extends Migration {
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+
+            DB::statement("
+                UPDATE records
+                SET data_pagamento = CASE
+                    WHEN date IS NOT NULL THEN date
+                    ELSE CURRENT_DATE()
+                END
+                WHERE data_pagamento IS NULL AND type='OUT'
+            ");
+
+            // Log the number of updated rows
+            $updatedRows = DB::select("
+                SELECT COUNT(*) as count FROM records
+                WHERE data_pagamento IS NOT NULL AND type='OUT'
+            ");
+            Log::info('Updated data_pagamento for OUT records: ' . $updatedRows[0]->count);
+
+
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        // No need to revert the data updates, but you could if needed
+        // In this case, we won't roll back the data fixes
+    }
+};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 176 - 176
public/assets/js/datatables.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 176 - 176
public/css/datatables.js


+ 95 - 0
public/css/style.css

@@ -16673,3 +16673,98 @@ div.dt-container div.dt-length label {
     background-color: #e9ecef;
     color: #495057;
 }
+
+
+/* CSS Ferrari - Modifiche UI */
+#home_logo {
+  height: 70px;
+}
+
+#sidebar--wrapper {
+  height: calc(100dvh - 86px);
+}
+
+#sidebar--wrapper #filter--section {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+#card--dashboard {
+  padding-block: 10px;
+  margin: 0;
+  overflow: auto;
+  height: calc(100dvh - 86px);
+  max-width: 100vw;
+}
+
+body:has(#filter--section.filterWrapper_open) #card--dashboard {
+  max-width: calc(100vw - 250px);
+}
+
+.row > [wire\:id] {
+  padding-inline: 0;
+}
+
+#resume-table {
+  width: 100% !important;
+  max-width: 100% !important;
+  padding: 0;
+  border: none;
+  max-height: calc(100dvh - 86px) !important;
+  /* overflow: auto; */
+}
+
+#resume-table.course_list-table {
+  height: calc(100dvh - (86px + 80px)) !important;
+}
+
+#resume-table.records-table {
+  height: calc(100dvh - (86px + 195px)) !important;
+}
+
+#card--dashboard:has(.showFilter.filter_shown) #resume-table.course_list-table {
+  height: calc(100dvh - (86px + 80px + 212px)) !important;
+}
+
+#resume-table.course_list-table > .row {
+  margin: 0;
+  position: sticky;
+  bottom: 0;
+  left: 0;
+  padding: 10px 0;
+  border-top: 1px solid;
+  z-index: 100;
+  background-color: white;
+}
+
+table.tablesaw thead:has(tr+tr) tr:first-child th {
+  padding-bottom: 0;
+}
+
+table.tablesaw thead:has(tr+tr) tr:last-child th {
+  padding-top: 0;
+}
+
+table.tableHead thead {
+  top: -10px !important;
+}
+
+.course_list-table table.tableHead thead,
+.records-table table.tableHead thead {
+  top: 0 !important;
+}
+
+#btn-back-to-top,
+#btn-back-to-bottom {
+  bottom: 10px;
+  right: 10px;
+  padding: 7px;
+  width: 40px;
+  height: 40px;
+}
+
+#btn-back-to-bottom {
+  top: unset;
+  right: 60px;
+}
+/* END CSS Ferrari - Modifiche UI */

+ 5 - 4
resources/views/layouts/app.blade.php

@@ -136,7 +136,7 @@
     <div class="row header--gestionale">
         <div class="header--gestionale_logo">
             <a href="/dashboard" class="d-flex align-items-center pb-2 pt-2">
-                <img src="{{env('LOGO2', env('LOGO', ''))}}" class="img-fluid" alt="logo madonnella"/>
+                <img src="{{env('LOGO2', env('LOGO', ''))}}" id="home_logo" class="img-fluid" alt="logo madonnella"/>
             </a>
         </div>
         <div class="header--gestionale_pageTitle d-flex align-items-center justify-content-between">
@@ -221,7 +221,8 @@
                     <i class="ico--ui hamburger--menu"></i>
             </a>
 
-            <div class="d-flex flex-column align-items-center align-items-sm-start min-vh-100 offcanvas-lg offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
+            <!-- <div class="d-flex flex-column align-items-center align-items-sm-start min-vh-100 offcanvas-lg offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel"> -->
+            <div class="d-flex flex-column align-items-center align-items-sm-start offcanvas-lg offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
                 @if(false)
                     <a href="/dashboard" class="d-flex align-items-center pb-2 pt-2 mb-md-0 me-md-auto text-white text-decoration-none">
                         <img src="{{env('LOGO2', env('LOGO', ''))}}" class="fs-5 d-none d-sm-inline img-fluid" alt="logo madonnella"  style="max-width:200px"/>
@@ -388,11 +389,11 @@
         <li class="user--boxlist_item">
             <a href="/profile">Profilo</a>
         </li>
-        @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
+{{--         @if(Auth::user()->level == env('LEVEL_ADMIN', 0))
             <li class="user--boxlist_item">
                 <a href="/azienda">Azienda</a>
             </li>
-        @endif
+        @endif --}}
         <li class="user--boxlist_item">
             <a href="/logout">Logout</a>
         </li>

+ 58 - 48
resources/views/livewire/course_list.blade.php

@@ -9,33 +9,41 @@
     </header>
 
 
-    <div class="row" style="margin-top: 10px; margin-bottom:10px;">
-        <div class="col-md-4">
-            <div class="col-md ">
-                <div class="dt-buttons btn-group flex-wrap">
-                    <div class="btn-group">
-                        <button class="btn btn-secondary buttons-collection" wire:click="export()" style="color:black !important">ESPORTA</button>
+    <div class="dt-container">
+
+        <div class="row" style="margin-top: 10px; margin-bottom:10px;">
+            <div class="col-md-4">
+                <div class="col-md ">
+                    <div class="dt-buttons btn-group flex-wrap">
+                        <div class="btn-group">
+                            <button class="btn btn-secondary buttons-collection" wire:click="export()" style="color:black !important">ESPORTA</button>
+                        </div>
                     </div>
                 </div>
             </div>
-        </div>
-        <div class="col-md-4">
-            <div class="row">
-                <div class="col-md-4" style="text-align:right">Visualizza</div>
-                <div class="col-md-4">
-                    <select name="tablesaw-350_length" aria-controls="tablesaw-350" class="form-select form-select-sm" id="dt-length-0" wire:model="pageLength">
-                        <option value="10">10</option>
-                        <option value="25">25</option>
-                        <option value="50">50</option>
-                        <option value="100">100</option>
-                        <option value="100000">Tutti</option>
-                    </select>
-                </div>
-                <div class="col-md-3">elementi</div>
+            <div class="col-md-4">
+                <!-- <div class="row"> -->
+                    <div class="dt-length">
+                        <label class="align-items-center d-flex dt-length-0 flex-row gap-2 justify-content-center">
+                            Visualizza
+                            <!-- <div class="col-md-4"> -->
+                                <select name="tablesaw-350_length" aria-controls="tablesaw-350" class="form-select form-select-sm m-0" id="dt-length-0" wire:model="pageLength">
+                                    <option value="10">10</option>
+                                    <option value="25">25</option>
+                                    <option value="50">50</option>
+                                    <option value="100">100</option>
+                                    <option value="100000">Tutti</option>
+                                </select>
+                            <!-- </div> -->
+                            <!-- <div class="col-md-3">elementi</div> -->
+                            elementi
+                        </label>
+                    </div>
+                <!-- </div> -->
+            </div>
+            <div class="col-md-4" style="text-align:right">
+                <a href="#" class="showHideFilter btn--ui" ><i class="fa-solid fa-sliders"></i></a><br>
             </div>
-        </div>
-        <div class="col-md-4" style="text-align:right">
-            <a href="#" class="showHideFilter btn--ui" ><i class="fa-solid fa-sliders"></i></a><br>
         </div>
     </div>
 
@@ -157,7 +165,8 @@
         </div>
     </div>
 
-    <section id="resume-table" class="scrollTable" style="margin-top:10px;">
+    <!-- <section id="resume-table" class="scrollTable" style="margin-top:10px;"> -->
+    <section id="resume-table" class="scrollTable course_list-table" style="margin-top:10px;">
         <div class="compare--chart_wrapper d-none"></div>
 
 
@@ -219,15 +228,15 @@
                 </tbody>
                 <tfoot id="checkall-target">
                     <tr>
-                        <th class="sticky-col-header first-zero"></th>
-                        <th class="sticky-col-header first-col"></th>
-                        <th class="sticky-col-header second-col"></th>
-                        <th class="sticky-col-header third-col"></th>
+                        <th class="sticky-col-header first-zero" style="border-bottom:none;"></th>
+                        <th class="sticky-col-header first-col" style="border-bottom:none;"></th>
+                        <th class="sticky-col-header second-col" style="border-bottom:none;"></th>
+                        <th class="sticky-col-header third-col" style="border-bottom:none;"></th>
                         @foreach($totS as $yyy)
                             @if (isset($yyy))
-                                <th style="padding-left:5px !important;padding-right:5px !important;">{!!$yyy!!}</th>
+                                <th style="padding-left:5px !important;padding-right:5px !important;border-bottom:none;">{!!$yyy!!}</th>
                             @else
-                                <th style="padding-left:5px !important;padding-right:5px !important;">aa</th>
+                                <th style="padding-left:5px !important;padding-right:5px !important;border-bottom:none;">aa</th>
                             @endif
                         @endforeach
 
@@ -566,11 +575,13 @@
                 {
                     isFilter = false;
                     $(".showFilter").hide();
+                    $(".showFilter").removeClass("filter_shown");
                 }
                 else
                 {
                     isFilter = true;
                     $(".showFilter").show();
+                    $(".showFilter").addClass("filter_shown");
                 }
             });
         } );
@@ -1226,15 +1237,6 @@
             @this.newPayment(selectedCourseId, months.toString(), selectedMemberId, selectedMemberCourseId, subscription);
         }
 
-        $( document ).ready( function(){
-
-            setMaxWidth();
-            setMaxHeight();
-            $( window ).bind( "resize", setMaxWidth );
-            $( window ).bind( "resize", setMaxHeight );
-
-        });
-
         function suspendPayment()
         {
             @this.suspendPayment(selectedCourseId, selectedMonth, selectedMemberId, selectedMemberCourseId, subscription);
@@ -1246,16 +1248,24 @@
         }
 
 
-        function setMaxWidth() {
-                 $("#resume-table").width( Math.round( $(window ).width() - size ) ) ;
-                 //$(".justify-content-between").css({"width": Math.round( $(window ).width() - size) + "px;"}); //.width( Math.round( $(window ).width() - size ) ) ;
+        // $( document ).ready( function(){
 
-            }
-            function setMaxHeight() {
-                console.log('height:' + $(window ).height() + 'px !important');
-                 //$("div.row.h-100").attr('style', 'height:' + ($(window ).height() + 50) + 'px !important');
-                 $("#resume-table").height( Math.round( $(window ).height() - 220 ) ) ;
-            }
+        //     setMaxWidth();
+        //     setMaxHeight();
+        //     $( window ).bind( "resize", setMaxWidth );
+        //     $( window ).bind( "resize", setMaxHeight );
+
+        // });
+
+        // function setMaxWidth() {
+        //     $("#resume-table").width( Math.round( $(window ).width() - size ) ) ;
+        //     //$(".justify-content-between").css({"width": Math.round( $(window ).width() - size) + "px;"}); //.width( Math.round( $(window ).width() - size ) ) ;
+        // }
+        // function setMaxHeight() {
+        //     console.log('height:' + $(window ).height() + 'px !important');
+        //     //$("div.row.h-100").attr('style', 'height:' + ($(window ).height() + 50) + 'px !important');
+        //     $("#resume-table").height( Math.round( $(window ).height() - 220 ) ) ;
+        // }
 
     </script>
 @endpush

+ 7 - 2
resources/views/livewire/payment_method.blade.php

@@ -111,8 +111,13 @@
                         <div class="row mb-3">
                             <div class="col">
                                 <div class="form--item">
-                                    <label for="inputName" class="form-label">Nome</label>
-                                    <input class="form-control js-keyupTitle @error('name') is-invalid @enderror" type="text" id="name" placeholder="Nome" wire:model="name">
+                                    <label for="name" class="form-label">Nome</label>
+                                    <select class="form-control @error('name') is-invalid @enderror" id="name" wire:model="name">
+                                        <option value="">Seleziona un metodo di pagamento</option>
+                                        @foreach($paymentMethods as $method)
+                                            <option value="{{ $method['name'] }}">{{ $method['name'] }} ({{ $method['code'] }})</option>
+                                        @endforeach
+                                    </select>
                                     @error('name')
                                         <div class="invalid-feedback">{{ $message }}</div>
                                     @enderror

+ 0 - 2
resources/views/livewire/receipt.blade.php

@@ -80,7 +80,6 @@
         </div>
         <hr size="1">
     </div>
-
     <section id="resume-table">
         <div class="compare--chart_wrapper d-none"></div>
 
@@ -135,7 +134,6 @@
 
 </div>
 
-
 @push('scripts')
     <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
     <style>

+ 11 - 11
resources/views/livewire/records.blade.php

@@ -65,7 +65,7 @@
               </div>
     </section>
 
-    <section id="resume-table"  class="scrollTable">
+    <section id="resume-table"  class="scrollTable records-table">
 
         <!--
         <canvas id="recordChart"></canvas>
@@ -90,11 +90,11 @@
                     <th scope="col" style="border-left:3px solid white;"></th>
                     @foreach($payments as $p)
                         @if($p->type == 'ALL')
-                            <th scope="col" style="text-align:right; border-left:3px solid white;">Entrate</th>
-                            <th scope="col" style="text-align:right">Uscite</th>
+                            <th scope="col" style="text-align:center; border-left:3px solid white;">Entrate</th>
+                            <th scope="col" style="text-align:center">Uscite</th>
                         @elseif($p->type == 'IN')
-                            <th scope="col" style="text-align:right; border-left:3px solid white;">Entrate</th>
-                            <th scope="col" style="text-align:right;"></th>
+                            <th scope="col" style="text-align:center; border-left:3px solid white;">Entrate</th>
+                            <th scope="col" style="text-align:center;"></th>
 
                         @elseif($p->type == 'OUT')
                             <th style="border-left:3px solid white;"></th>
@@ -251,8 +251,8 @@
             background-color: #0C6197;
             color: white;
             position: fixed;
-            bottom: 20px;
-            right: 20px;
+            /* bottom: 20px; */
+            /* right: 20px; */
             display: none;
         }
 
@@ -260,8 +260,8 @@
             background-color: #0C6197;
             color: white;
             position: fixed;
-            top: 120px;
-            right: 20px;
+            /* top: 120px; */
+            /* right: 20px; */
             z-index: 9999;
             display: none;
         }
@@ -473,11 +473,11 @@
         });
 
             function setMaxWidth() {
-                $("#resume-table").width( Math.round( $(window ).width() - size ) ) ;
+                // $("#resume-table").width( Math.round( $(window ).width() - size ) ) ;
             }
 
             function setMaxHeight() {
-                 $("#resume-table").height( Math.round( $(window ).height() - 300 ) ) ;
+                //  $("#resume-table").height( Math.round( $(window ).height() - 300 ) ) ;
             }
 
             let mybuttonBottom = document.getElementById("btn-back-to-bottom");

+ 8 - 1
resources/views/livewire/records_in_out.blade.php

@@ -30,7 +30,14 @@
 
         </form>
         @if(sizeof($columns) < 6)
-            <button class="btn--ui show" id="addButton" style="margin-left:5px;">aggiungi</button>
+            <button class="btn--ui show" id="addButton" style="margin-left:5px;">
+                <span wire:loading wire:target="show">
+                    <i class="fas fa-spinner fa-spin"></i>
+                </span>
+                <span wire:loading.remove wire:target="show">
+                    aggiungi
+                </span>
+            </button>
         @endif
 
             <button class="btn--ui lightGrey reset reset" onClick="window.location.reload();" style="margin-left:5px;">reset</button>

+ 215 - 6
resources/views/livewire/records_out.blade.php

@@ -20,6 +20,53 @@
 
     @if(!$add && !$update)
 
+    <div class="title--section_addButton d-flex justify-content-end">
+        <button type="button" class="btn--ui entrata"
+                wire:click="openImportModal" onclick="openImportModal()">
+            Importa
+        </button>
+    </div>
+
+        <div class="modal fade" id="importModal" tabindex="-1" aria-labelledby="importModalLabel" aria-hidden="true"
+     wire:ignore.self>
+        <div class="modal-dialog">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title" id="importModalLabel">Importa Ricevute</h5>
+                    <button type="button" class="btn-close" onclick="closeImportModal()" aria-label="Close"></button>
+                </div>
+                <div class="modal-body">
+                    <form wire:submit.prevent="importReceipts">
+                        <div class="mb-3" wire:ignore>
+                            <label for="selectedCausal" class="form-label">Seleziona Causale di Uscita</label>
+                            <select class="form-select import-causal-select" id="selectedCausal" wire:model.defer="selectedCausal">
+                                <option value="">Seleziona una causale</option>
+                                @forelse($importCausals as $causal)
+                                    <option value="{{ $causal['id'] }}">{{ $causal['name'] }}</option>
+                                @empty
+                                    <option value="" disabled>Nessuna causale disponibile</option>
+                                @endforelse
+                            </select>
+                            @error('selectedCausal') <span class="text-danger">{{ $message }}</span> @enderror
+                        </div>
+                        <div class="mb-3">
+                            <label for="receiptFiles" class="form-label">Seleziona Files</label>
+                            <input type="file" class="form-control" id="receiptFiles" wire:model="receiptFiles" multiple>
+                            @error('receiptFiles.*') <span class="text-danger">{{ $message }}</span> @enderror
+                            <small class="form-text text-muted">Massimo {{ ini_get('max_file_uploads') }} file consentiti.</small>
+                        </div>
+                        <div class="progress mb-2" wire:ignore>
+                            <div class="progress-bar" role="progressbar" style="width: 0%" aria-valuenow="0"
+                                 aria-valuemin="0" aria-valuemax="100">0%
+                            </div>
+                        </div>
+                        <button type="submit" class="btn--ui">Importa</button>
+                        <button type="button" class="btn--ui lightGrey" onclick="closeImportModal()">Annulla</button>
+                    </form>
+                </div>
+            </div>
+        </div>
+    </div>
 
 
         <section id="subheader" class="d-flex align-items-center justify-content-between">
@@ -126,7 +173,7 @@
                 <thead>
                     <tr>
                         <!--<th scope="col"></th>-->
-                        <th scope="col">Data pagamento</th>
+                        <th scope="col">Data</th>
                         <th scope="col">Importo</th>
                         <th scope="col">Fornitore</th>
                         <th scope="col">Causale</th>
@@ -212,12 +259,21 @@
                             </div>
 
                             <div class="col-md-6">
-                                <span class="title-form d-block w-100">Data di Pagamento</span>
+                                <span class="title-form d-block w-100">Data</span>
                                 <div class="input-group mb-3">
                                     <input id="date" type="date" class="form-control"  wire:model="date">
                                 </div>
                             </div>
 
+
+                            <div class="col-md-6">
+                                <span class="title-form d-block w-100">Data Pagamento</span>
+                                <div class="input-group mb-3">
+                                    <input id="datePagamento" type="date" class="form-control"  wire:model="data_pagamento">
+                                </div>
+                            </div>
+
+
                             <div class="col-12">
                                 <span class="title-form d-block w-100">Fornitore</span>
 
@@ -283,6 +339,48 @@
                                 </div>
                             </div>
 
+                            <div class="row gx-2 mt-5 align-items-center">
+                                <div class="col-md-6">
+                                    <span class="total primary">Imponibile</span>
+                                </div>
+                                <div class="col-md-6">
+                                    @if($add)
+                                        <input type="text" class="form-control totalInput text-end @error('rows.{{$idx}}.imponibile') is-invalid @enderror"
+                                            id="rows.{{$idx}}.imponibile" wire:model="rows.{{$idx}}.imponibile"
+                                            wire:keydown.enter="store(false)" onkeyup="onlyNumberAmount(this)" placeholder="€ 0,00">
+                                    @endif
+                                    @if($update)
+                                        <input type="text" class="form-control totalInput text-end @error('rows.{{$idx}}.imponibile') is-invalid @enderror"
+                                            id="rows.{{$idx}}.imponibile" placeholder="€ 0,00" wire:model="rows.{{$idx}}.imponibile"
+                                            onkeyup="onlyNumberAmount(this)" wire:keydown.enter="update(false)">
+                                    @endif
+                                    @error('rows.'. $idx . '.imponibile')
+                                        <span style="margin-top: 0.25rem; font-size: 0.875em; color: var(--bs-form-invalid-color);">{{ $message }}</span>
+                                    @enderror
+                                </div>
+                            </div>
+
+                            <div class="row gx-2 mt-5 align-items-center">
+                                <div class="col-md-6">
+                                    <span class="total primary">Aliquota IVA (%)</span>
+                                </div>
+                                <div class="col-md-6">
+                                    @if($add)
+                                        <input type="text" class="form-control text-end @error('rows.{{$idx}}.aliquota_iva') is-invalid @enderror"
+                                            id="rows.{{$idx}}.aliquota_iva" wire:model="rows.{{$idx}}.aliquota_iva"
+                                            wire:keydown.enter="store(false)" onkeyup="onlyNumberPercent(this)" placeholder="0%">
+                                    @endif
+                                    @if($update)
+                                        <input type="text" class="form-control text-end @error('rows.{{$idx}}.aliquota_iva') is-invalid @enderror"
+                                            id="rows.{{$idx}}.aliquota_iva" placeholder="0%" wire:model="rows.{{$idx}}.aliquota_iva"
+                                            onkeyup="onlyNumberPercent(this)" wire:keydown.enter="update(false)">
+                                    @endif
+                                    @error('rows.'. $idx . '.aliquota_iva')
+                                        <span style="margin-top: 0.25rem; font-size: 0.875em; color: var(--bs-form-invalid-color);">{{ $message }}</span>
+                                    @enderror
+                                </div>
+                            </div>
+
 
                             <div class="row gx-2 mt-5 align-items-center">
                                 <div class="col-md-6">
@@ -444,7 +542,7 @@
                             </ul>
                         @endif
                         <ul class="resume-item date p-0">
-                            <li><strong>Data di Pagamento</strong></li>
+                            <li><strong>Data</strong></li>
                             <li>{{ date("d/m/Y", strtotime($date)) }}</li>
                         </ul>
                         @if($this->causal)
@@ -740,10 +838,11 @@
             @this.edit(id);
         }
 
-        function deleteData(id)
-        {
+        function deleteData(id) {
             if (confirm('Sei sicuro?'))
-                @this.delete(id);
+                @this.delete(id).then(() => {
+                    window.location.reload();
+                });
         }
 
         Livewire.on('load-data-table', () => {
@@ -937,6 +1036,116 @@
 
         };
 
+        document.addEventListener('livewire:initialized', () => {
+            let importModalOpen = false;
+            const importModal = document.getElementById('importModal');
+
+            importModal.addEventListener('shown.bs.modal', function () {
+                importModalOpen = true;
+            });
+
+            importModal.addEventListener('hidden.bs.modal', function () {
+                importModalOpen = false;
+            });
+
+            document.addEventListener('livewire:update', function() {
+                if (importModalOpen) {
+                    const modalInstance = bootstrap.Modal.getInstance(importModal);
+                    if (!modalInstance) {
+                        const newModal = new bootstrap.Modal(importModal);
+                        newModal.show();
+                    } else if (!importModal.classList.contains('show')) {
+                        modalInstance.show();
+                    }
+                }
+            });
+
+            document.querySelectorAll('.select2-container').forEach(select => {
+                select.addEventListener('click', function(e) {
+                    e.stopPropagation();
+                });
+            });
+        });
+
+        function initImportCausalSelect() {
+            $('.import-causal-select').select2({
+                dropdownParent: $('#importModal'),
+                language: {
+                    noResults: function() {
+                        return "Nessun risultato";
+                    }
+                }
+            });
+
+            $('.import-causal-select').on('change', function() {
+                let selectedValue = $(this).val();
+                Livewire.first().set('selectedCausal', selectedValue);
+            });
+        }
+
+    // Function to open the modal
+    function openImportModal() {
+        const importModal = new bootstrap.Modal(document.getElementById('importModal'));
+        importModal.show();
+
+        setTimeout(function() {
+            initImportCausalSelect();
+        }, 200);
+    }
+
+    document.addEventListener('DOMContentLoaded', function() {
+        if (document.getElementById('importModal')) {
+            initImportCausalSelect();
+        }
+
+
+        Livewire.on('load-select', function() {
+            if (document.getElementById('importModal') &&
+                document.getElementById('importModal').classList.contains('show')) {
+                initImportCausalSelect();
+            }
+        });
+    });
+
+    function closeImportModal() {
+        const importModal = bootstrap.Modal.getInstance(document.getElementById('importModal'));
+        if (importModal) {
+            importModal.hide();
+        }
+        setTimeout(function() {
+            window.location.reload();
+        }, 100);
+    }
+
+    Livewire.on('update-progress', (progress) => {
+        const progressBar = document.querySelector('.progress-bar');
+        progressBar.style.width = `${progress}%`;
+        progressBar.setAttribute('aria-valuenow', progress);
+        progressBar.textContent = `${progress}%`;
+    });
+
+    Livewire.on('import-started', () => {
+        window.selectedCausalValue = $('.import-causal-select').val();
+
+        $('.import-causal-select').prop('disabled', true);
+    });
+
+    Livewire.on('import-finished', () => {
+        $('.import-causal-select').prop('disabled', false);
+        $('.import-causal-select').val(window.selectedCausalValue).trigger('change');
+
+    });
+
+    function onlyNumberPercent(input) {
+        let v = input.value.replace(/[^\d]/g, '');
+        if (v.length > 3) v = v.slice(0, 3);
+
+        // Ensure percentage doesn't exceed 100
+        if (parseInt(v) > 100) v = '100';
+
+        input.value = v + "%";
+    }
+
     </script>
 
 @endpush

+ 11 - 6
routes/web.php

@@ -81,6 +81,7 @@ Route::group(['middleware' => 'auth'], function () {
     Route::get('/profile', \App\Http\Livewire\Profile::class);
     Route::get('/rates', \App\Http\Livewire\Rate::class);
     Route::get('/reports', \App\Http\Livewire\Reports::class);
+    Route::get('/azienda', \App\Http\Livewire\Azienda::class);
 });
 
 Route::get('/receipt/{id}', function ($id) {
@@ -1435,8 +1436,10 @@ Route::get('/get_course_members', function () {
 });
 
 Route::get('/get_receipts', function () {
-    $x = \App\Models\Receipt::select('receipts.*', 'members.first_name', 'members.last_name')
-        ->leftJoin('members', 'receipts.member_id', '=', 'members.id');
+    $x = \App\Models\Receipt::select('receipts.*', 'members.first_name', 'members.last_name', DB::raw('SUM(receipts_rows.amount) AS totals'))
+        ->leftJoin('members', 'receipts.member_id', '=', 'members.id')
+        ->leftJoin('receipts_rows', 'receipts.id', '=', 'receipts_rows.receip_id')
+        ->groupBy('receipts.id', 'members.first_name', 'members.last_name');
 
     if (isset($_GET["search"]["value"])) {
         $v = str_replace("'", "\'", stripcslashes($_GET["search"]["value"]));
@@ -1475,12 +1478,14 @@ Route::get('/get_receipts', function () {
             $column = 'status';
         if ($_GET["order"][0]["column"] == 5)
             $column = 'date';
+        if ($_GET["order"][0]["column"] == 6)
+            $column = 'totals';
         if ($column != '')
-            $x = $x->orderBy($column, $_GET["order"][0]["dir"])->orderBy('id', 'DESC');
+            $x = $x->orderBy($column, $_GET["order"][0]["dir"])->orderBy('receipts.id', 'DESC');
         else
-            $x = $x->orderBy('id', 'DESC');
+            $x = $x->orderBy('receipts.id', 'DESC');
     } else
-        $x = $x->orderBy('id', 'DESC');
+        $x = $x->orderBy('receipts.id', 'DESC');
 
     if (isset($_GET["start"]))
         $x = $x->offset($_GET["start"])->limit($_GET["length"])->get();
@@ -1497,7 +1502,7 @@ Route::get('/get_receipts', function () {
             'first_name' => $r->member->first_name,
             'status' => $r->status,
             'date' => date("d/m/Y", strtotime($r->created_at)),
-            'totals' => formatPrice($r->rows->sum('amount')),
+            'totals' => formatPrice($r->totals),
             'action' => $ids
         );
     }

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio