Explorar o código

nuovo modulo - Movimenti Finanziari

ferrari hai 1 mes
pai
achega
8ce694f40f

+ 277 - 0
app/Http/Livewire/FinancialMovements.php

@@ -0,0 +1,277 @@
+<?php
+
+namespace App\Http\Livewire;
+
+use Livewire\Component;
+
+class FinancialMovements extends Component
+{
+    public $origins = [];
+    public $destinations = [];
+
+    public $date;
+    public $origin_id;
+    public $destination_id;
+    public $causal_id;
+    public $amount;
+    public $amountFormatted;
+    public $notes;
+
+    public $causal_name;
+
+    public $add = false;
+    public $update = false;
+
+    public $isDuplicate = false;
+
+    public $dataId;
+
+    public $multipleIds = [];
+    public $multipleAction = '';
+
+    protected function rules()
+    {
+        return [
+            'date' => ['required', 'date'],
+            'origin_id' => ['required', 'integer', 'exists:banks,id'],
+            'destination_id' => ['required', 'integer', 'exists:banks,id', 'different:origin_id',],
+            'amount' => ['required', 'numeric', 'gt:0'],
+            'notes' => ['nullable', 'string', 'max:5000'],
+        ];
+    }
+
+    protected $messages = [
+        'date.required' => "La data dell'operazione è obbligatoria.",
+        'origin_id.required' => "Seleziona un conto di origine.",
+        'origin_id.exists' => "Il conto di origine selezionato non è valido.",
+        'destination_id.required' => "Seleziona un conto di destinazione.",
+        'destination_id.exists' => "Il conto di destinazione selezionato non è valido.",
+        'destination_id.different' => "Origine e destinazione devono essere diversi.",
+        'amount.required' => "Inserisci un importo.",
+        'amount.numeric' => "L'importo deve essere un numero.",
+        'amount.gt' => "L'importo deve essere maggiore di zero.",
+    ];
+
+    public function hydrate()
+    {
+        $this->emit('load-select');
+    }
+
+    public function resetFields()
+    {
+        $this->date = date("Y-m-d");
+        $this->origin_id = null;
+        $this->destination_id = null;
+        $this->amount = null;
+        $this->amountFormatted = null;
+        $this->notes = null;
+
+        $this->emit('load-data-table');
+    }
+
+    public function mount()
+    {
+        $this->origins = \App\Models\Bank::where('enabled', true)->whereIn('visibility', ['ALL', 'OUT'])->orderBy('name')->get();
+        $this->destinations = \App\Models\Bank::where('enabled', true)->whereIn('visibility', ['ALL', 'IN'])->orderBy('name')->get();
+
+        $this->causal_name = "PAGAMENTO MOVIMENTO";
+        $this->causal_id = \App\Models\Causal::where('name', $this->causal_name)->value('id');
+        if (!$this->causal_id) {
+            $causal = new \App\Models\Causal();
+            $causal->name = $this->causal_name;
+            $causal->type = "IN";
+            $causal->parent_id = null;
+            $causal->money = false;
+            $causal->corrispettivo_fiscale = false;
+            $causal->no_receipt = false;
+            $causal->user_status = false;
+            $causal->no_first = false;
+            $causal->no_records = false;
+            $causal->enabled = true;
+            $causal->save();
+
+            $this->causal_id = $causal->id;
+        }
+    }
+
+    public function render()
+    {
+        return view('livewire.financial_movements');
+    }
+
+    public function add()
+    {
+        $this->emit('load-select');
+
+        $this->resetFields();
+
+        $this->dataId = 0;
+        $this->add = true;
+        $this->update = false;
+
+        $this->emit('setEdit', true);
+    }
+
+    public function store()
+    {
+        if ($this->validate()) {
+            try {
+                $financial_movement = \App\Models\FinancialMovement::create([
+                    'date' => $this->date,
+                    'origin_id' => $this->origin_id,
+                    'destination_id' => $this->destination_id,
+                    'causal_id' => $this->causal_id,
+                    'amount' => $this->amount,
+                    'notes' => $this->notes,
+                ]);
+                $this->dataId = $financial_movement->id;
+
+                session()->flash('success', 'Movimento creato');
+
+                $this->resetFields();
+                $this->add = false;
+                $this->isDuplicate = false;
+                $this->emit('setEdit', false);
+            } catch (\Exception $ex) {
+                session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
+            }
+        }
+    }
+
+    public function duplicate($id)
+    {
+        $financial_movement = \App\Models\FinancialMovement::findOrFail($id);
+        $new_financial_movement = $financial_movement->replicate();
+        $new_financial_movement->save();
+
+        $this->edit($new_financial_movement->id);
+
+        $this->isDuplicate = true;
+    }
+
+    public function edit($id)
+    {
+        $this->emit('setEdit', true);
+
+        $this->emit('load-select');
+        try {
+            $financial_movement = \App\Models\FinancialMovement::findOrFail($id);
+            if (!$financial_movement) {
+                session()->flash('error', 'Movimento non trovato');
+            } else {
+                $this->date = date("Y-m-d", strtotime($financial_movement->date));;
+                $this->origin_id = $financial_movement->origin_id;
+                $this->destination_id = $financial_movement->destination_id;
+                $this->amount = $financial_movement->amount;
+                $this->amountFormatted = formatPrice($this->amount);
+                $this->notes = $financial_movement->notes;
+
+                $this->dataId = $financial_movement->id;
+                $this->update = true;
+                $this->add = false;
+            }
+        } catch (\Exception $ex) {
+            session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
+        }
+    }
+
+    public function update()
+    {
+        if ($this->validate()) {
+            try {
+                \App\Models\FinancialMovement::whereId($this->dataId)->update([
+                    'date' => $this->date,
+                    'origin_id' => $this->origin_id,
+                    'destination_id' => $this->destination_id,
+                    'amount' => $this->amount,
+                    'notes' => $this->notes,
+                ]);
+    
+                session()->flash('success', 'Movimento aggiornato');
+    
+                $this->resetFields();
+                $this->update = false;
+                $this->isDuplicate = false;
+                $this->emit('setEdit', false);
+            } catch (\Exception $ex) {
+                session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
+            }
+        }
+    }
+
+    public function cancel()
+    {
+        if ($this->isDuplicate) {
+            try {
+                \App\Models\FinancialMovement::find($this->dataId)->delete();
+                session()->flash('success', "Movimento eliminato");
+            } catch (\Exception $e) {
+                session()->flash('error', 'Errore (' . $e->getMessage() . ')');
+            }
+        }
+
+        $this->isDuplicate = false;
+        $this->add = false;
+        $this->update = false;
+        $this->resetFields();
+        $this->emit('setEdit', false);
+
+        return redirect()->to('/financial_movements');
+    }
+
+    public function delete($id)
+    {
+        try {
+            $fm = \App\Models\FinancialMovement::find($id);
+            $fm->deleted = true;
+            $fm->save();
+
+            session()->flash('success', 'Movimento eliminato');
+
+            $this->resetFields();
+            $this->update = false;
+            $this->isDuplicate = false;
+            $this->emit('setEdit', false);
+
+            $this->emit('reload');
+        } catch (\Exception $ex) {
+            session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
+        }
+    }
+
+    public function multipleDelete()
+    {
+        try {
+            foreach ($this->multipleIds as $id) {
+                $fm = \App\Models\FinancialMovement::find($id);
+                $fm->deleted = true;
+                $fm->save();
+            }
+        } catch (\Exception $e) {
+            session()->flash('error', 'Errore (' . $e->getMessage() . ')');
+        }
+        $this->multipleAction = '';
+    }
+
+    public function updatedAmountFormatted($value)
+    {
+        $clean = str_replace(['€', '.', ' '], '', $value);
+        $clean = str_replace(',', '.', $clean);
+
+        $this->amount = is_numeric($clean) ? (float) $clean : null;
+    }
+
+    public function updatedOriginId()
+    {
+        if ($this->origin_id && $this->destination_id && $this->origin_id == $this->destination_id) {
+            $this->destination_id = null;
+        }
+    }
+
+    public function updatedDestinationId()
+    {
+        if ($this->origin_id && $this->destination_id && $this->origin_id == $this->destination_id) {
+            $this->destination_id = null;
+        }
+    }
+}

+ 131 - 22
app/Http/Livewire/Record.php

@@ -601,7 +601,6 @@ class Record extends Component
 
     public function loadData($from, $to)
     {
-
         $exclude_from_records = \App\Models\Member::where('exclude_from_records', true)->pluck('id')->toArray();
 
         $f = $from != '' ? $from : $this->appliedFromDate;
@@ -644,6 +643,17 @@ class Record extends Component
                     });
             });
 
+        $financial_movements = \App\Models\FinancialMovement::select(
+                'financial_movements.*',
+                'causals.name as causal_name',
+                'd.name as destination',
+                'o.name as origin',
+            )
+            ->join('causals', 'financial_movements.causal_id', '=', 'causals.id')
+            ->leftJoin('banks as d', 'financial_movements.destination_id', '=', 'd.id')
+            ->leftJoin('banks as o', 'financial_movements.origin_id', '=', 'o.id')
+            ->whereBetween('date', [$f . " 00:00:00", $t . " 23:59:59"]);
+
         if ($this->filterCausals != null && sizeof($this->filterCausals) > 0) {
             $causals = array();
             foreach ($this->filterCausals as $z) {
@@ -658,24 +668,38 @@ class Record extends Component
                 }
             }
             $datas->whereIn('causal_id', $causals);
+
+            $financial_movements->whereIn('financial_movements.causal_id', $causals);
         }
         if ($this->filterPaymentMethods != null && sizeof($this->filterPaymentMethods) > 0) {
             $datas->whereIn('payment_method_id', $this->filterPaymentMethods);
+
+            $financial_movements->whereRaw('0 = 1');
         }
         if ($this->filterOrigins != null && sizeof($this->filterOrigins) > 0) {
             $datas->whereIn('origin_id', $this->filterOrigins);
+
+            $financial_movements->whereIn('financial_movements.origin_id', $this->filterOrigins);
         }
         if ($this->filterDestinations != null && sizeof($this->filterDestinations) > 0) {
             $datas->whereIn('destination_id', $this->filterDestinations);
+
+            $financial_movements->whereIn('financial_movements.destination_id', $this->filterDestinations);
         }
         if ($this->filterMember != null && $this->filterMember > 0) {
             $datas->where('member_id', $this->filterMember);
+
+            $financial_movements->whereRaw('0 = 1');
         }
         $datas = $datas->orderBy('date', 'ASC')
             ->orderBy('records.created_at', 'ASC')
             ->orderBy('records_rows.id', 'ASC')
             ->get();
 
+        $financial_movements = $financial_movements->orderBy('date', 'ASC')
+            ->orderBy('financial_movements.created_at', 'ASC')
+            ->get();
+
         $ret = array();
 
         $this->total_in = 0;
@@ -698,6 +722,50 @@ class Record extends Component
             }
         }
 
+        foreach ($financial_movements as $m) {
+            // USCITA
+            $ret[] = (object) [
+                'id' => 'fm_out_' . $m->id,
+                'date' => $m->date,
+                'type' => 'MOVE_OUT',
+                'commercial' => false,
+                'causal_name' => $m->causal_name,
+                'amount' => $m->amount,
+                'origin' => $m->origin,
+                'destination' => null,
+                'deleted' => $m->deleted,
+            ];
+
+            $this->total_out += $m->amount;
+
+            // ENTRATA
+            $ret[] = (object) [
+                'id' => 'fm_in_' . $m->id,
+                'date' => $m->date,
+                'type' => 'MOVE_IN',
+                'commercial' => false,
+                'causal_name' => $m->causal_name,
+                'amount' => $m->amount,
+                'origin' => null,
+                'destination' => $m->destination,
+                'deleted' => $m->deleted,
+            ];
+
+            $this->total_in += $m->amount;
+        }
+
+        usort($ret, function ($a, $b) {
+            $da = $a->date ? strtotime((string)$a->date) : 0;
+            $db = $b->date ? strtotime((string)$b->date) : 0;
+            if ($da !== $db) return $da <=> $db;
+
+            $ca = isset($a->created_at) && $a->created_at ? strtotime((string)$a->created_at) : 0;
+            $cb = isset($b->created_at) && $b->created_at ? strtotime((string)$b->created_at) : 0;
+            if ($ca !== $cb) return $ca <=> $cb;
+
+            return ((int)($a->id ?? 0)) <=> ((int)($b->id ?? 0));
+        });
+
         if ($this->total_in > 0 || $this->total_out > 0)        
         {
             $ret[] = (object) array("date" => "", "total_in" => $this->total_in, "total_out" => $this->total_out);
@@ -1763,34 +1831,75 @@ class Record extends Component
         $activeWorksheet->getStyle('A1:J1')->getFont()->getColor()->setARGB('FFFFFFFF');
 
         $idx = 2;
-        foreach($records as $record)
-        {
-            if ($record->date != '')
-            {
+        foreach ($records as $record) {
+            if ($record->date != '') {
+
+                $isMoveIn  = $record->type === 'MOVE_IN';
+                $isMoveOut = $record->type === 'MOVE_OUT';
+                $isIn  = $record->type === 'IN';
+                $isOut = $record->type === 'OUT';
+
                 $activeWorksheet->setCellValue('A' . $idx, date("d/m/Y", strtotime($record->date)));
-                $activeWorksheet->setCellValue('B' . $idx, $record->commercial ? 'Commerciale' : 'Non commerciale');
+
+                // Tipologia
+                $activeWorksheet->setCellValue(
+                    'B' . $idx,
+                    ($isMoveIn || $isMoveOut) ? '' : ($record->commercial ? 'Commerciale' : 'Non commerciale')
+                );
+
+                // Causale
                 $activeWorksheet->setCellValue('C' . $idx, $record->causal_name);
-                $activeWorksheet->setCellValue('D' . $idx, $record->type == 'IN' ? ($record->member->first_name . " " . $record->member->last_name) : @$record->supplier->name);
+
+                // Nominativo
+                if ($isIn && isset($record->member)) {
+                    $nominativo = $record->member->first_name . ' ' . $record->member->last_name;
+                } elseif ($isOut && isset($record->supplier)) {
+                    $nominativo = $record->supplier->name;
+                } else {
+                    $nominativo = '';
+                }
+                $activeWorksheet->setCellValue('D' . $idx, $nominativo);
+
+                // Stato
                 $activeWorksheet->setCellValue('E' . $idx, $record->deleted ? 'Annullata' : '');
-                $activeWorksheet->setCellValue('F' . $idx, $record->type == 'IN' ? formatPrice($record->amount) : '');
-                $activeWorksheet->setCellValue('G' . $idx, $record->type == 'OUT' ? formatPrice($record->amount) : '');
-                $activeWorksheet->setCellValue('H' . $idx, $record->type == 'OUT' ? $record->origin : '');
-                $activeWorksheet->setCellValue('I' . $idx, $record->type == 'IN' ? $record->destination : '');
-                $activeWorksheet->setCellValue('J' . $idx, $record->payment_method->name);
-            }
-            else
-            {
+
+                // Entrata
+                $activeWorksheet->setCellValue(
+                    'F' . $idx,
+                    ($isIn || $isMoveIn) ? formatPrice($record->amount) : ''
+                );
+
+                // Uscita
+                $activeWorksheet->setCellValue(
+                    'G' . $idx,
+                    ($isOut || $isMoveOut) ? formatPrice($record->amount) : ''
+                );
+
+                // Origine
+                $activeWorksheet->setCellValue(
+                    'H' . $idx,
+                    ($isOut || $isMoveOut) ? ($record->origin ?? '') : ''
+                );
+
+                // Destinazione
+                $activeWorksheet->setCellValue(
+                    'I' . $idx,
+                    ($isIn || $isMoveIn) ? ($record->destination ?? '') : ''
+                );
+
+                // Metodo di pagamento
+                $activeWorksheet->setCellValue(
+                    'J' . $idx,
+                    ($isMoveIn || $isMoveOut) ? '' : ($record->payment_method->name ?? '')
+                );
+
+            } else {
+                // RIGA TOTALI
                 $activeWorksheet->setCellValue('A' . $idx, "Totali");
-                $activeWorksheet->setCellValue('B' . $idx, "");
-                $activeWorksheet->setCellValue('C' . $idx, "");
-                $activeWorksheet->setCellValue('D' . $idx, "");
-                $activeWorksheet->setCellValue('E' . $idx, "");
                 $activeWorksheet->setCellValue('F' . $idx, formatPrice($record->total_in));
                 $activeWorksheet->setCellValue('G' . $idx, formatPrice($record->total_out));
-                $activeWorksheet->setCellValue('H' . $idx, "");
-                $activeWorksheet->setCellValue('I' . $idx, "");
-                $activeWorksheet->setCellValue('J' . $idx, "");
             }
+
             $idx++;
         }
 

+ 62 - 21
app/Jobs/ExportPrimaNota.php

@@ -191,34 +191,75 @@ class ExportPrimaNota implements ShouldQueue
         $activeWorksheet->getStyle('A1:J1')->getFont()->getColor()->setARGB('FFFFFFFF');
 
         $idx = 2;
-        foreach($this->records as $record)
-        {
-            if ($record->date != '')
-            {
+        foreach ($this->records as $record) {
+            if ($record->date != '') {
+
+                $isMoveIn  = $record->type === 'MOVE_IN';
+                $isMoveOut = $record->type === 'MOVE_OUT';
+                $isIn  = $record->type === 'IN';
+                $isOut = $record->type === 'OUT';
+
                 $activeWorksheet->setCellValue('A' . $idx, date("d/m/Y", strtotime($record->date)));
-                $activeWorksheet->setCellValue('B' . $idx, $record->commercial ? 'Commerciale' : 'Non commerciale');
+
+                // Tipologia
+                $activeWorksheet->setCellValue(
+                    'B' . $idx,
+                    ($isMoveIn || $isMoveOut) ? '' : ($record->commercial ? 'Commerciale' : 'Non commerciale')
+                );
+
+                // Causale
                 $activeWorksheet->setCellValue('C' . $idx, $record->causal_name);
-                $activeWorksheet->setCellValue('D' . $idx, $record->type == 'IN' ? ($record->member->first_name . " " . $record->member->last_name) : @$record->supplier->name);
+
+                // Nominativo
+                if ($isIn && isset($record->member)) {
+                    $nominativo = $record->member->first_name . ' ' . $record->member->last_name;
+                } elseif ($isOut && isset($record->supplier)) {
+                    $nominativo = $record->supplier->name;
+                } else {
+                    $nominativo = '';
+                }
+                $activeWorksheet->setCellValue('D' . $idx, $nominativo);
+
+                // Stato
                 $activeWorksheet->setCellValue('E' . $idx, $record->deleted ? 'Annullata' : '');
-                $activeWorksheet->setCellValue('F' . $idx, $record->type == 'IN' ? formatPrice($record->amount) : '');
-                $activeWorksheet->setCellValue('G' . $idx, $record->type == 'OUT' ? formatPrice($record->amount) : '');
-                $activeWorksheet->setCellValue('H' . $idx, $record->type == 'OUT' ? $record->origin : '');
-                $activeWorksheet->setCellValue('I' . $idx, $record->type == 'IN' ? $record->destination : '');
-                $activeWorksheet->setCellValue('J' . $idx, $record->payment_method->name);
-            }
-            else
-            {
+
+                // Entrata
+                $activeWorksheet->setCellValue(
+                    'F' . $idx,
+                    ($isIn || $isMoveIn) ? formatPrice($record->amount) : ''
+                );
+
+                // Uscita
+                $activeWorksheet->setCellValue(
+                    'G' . $idx,
+                    ($isOut || $isMoveOut) ? formatPrice($record->amount) : ''
+                );
+
+                // Origine
+                $activeWorksheet->setCellValue(
+                    'H' . $idx,
+                    ($isOut || $isMoveOut) ? ($record->origin ?? '') : ''
+                );
+
+                // Destinazione
+                $activeWorksheet->setCellValue(
+                    'I' . $idx,
+                    ($isIn || $isMoveIn) ? ($record->destination ?? '') : ''
+                );
+
+                // Metodo di pagamento
+                $activeWorksheet->setCellValue(
+                    'J' . $idx,
+                    ($isMoveIn || $isMoveOut) ? '' : ($record->payment_method->name ?? '')
+                );
+
+            } else {
+                // RIGA TOTALI
                 $activeWorksheet->setCellValue('A' . $idx, "Totali");
-                $activeWorksheet->setCellValue('B' . $idx, "");
-                $activeWorksheet->setCellValue('C' . $idx, "");
-                $activeWorksheet->setCellValue('D' . $idx, "");
-                $activeWorksheet->setCellValue('E' . $idx, "");
                 $activeWorksheet->setCellValue('F' . $idx, formatPrice($record->total_in));
                 $activeWorksheet->setCellValue('G' . $idx, formatPrice($record->total_out));
-                $activeWorksheet->setCellValue('H' . $idx, "");
-                $activeWorksheet->setCellValue('I' . $idx, "");
-                $activeWorksheet->setCellValue('J' . $idx, "");
             }
+
             $idx++;
         }
 

+ 38 - 0
app/Models/FinancialMovement.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class FinancialMovement extends Model
+{
+    use HasFactory;
+
+    protected $table = 'financial_movements';
+
+    protected $fillable = [
+        'date',
+        'origin_id',
+        'destination_id',
+        'amount',
+        'causal_id',
+        'notes',
+        'deleted',
+    ];
+
+    public function origin()
+    {
+        return $this->belongsTo(\App\Models\Bank::class, 'origin_id');
+    }
+
+    public function destination()
+    {
+        return $this->belongsTo(\App\Models\Bank::class, 'destination_id');
+    }
+
+    public function causal()
+    {
+        return $this->belongsTo(\App\Models\Causal::class, 'causal_id');
+    }
+}

+ 40 - 0
database/migrations/2025_12_17_155046_create_financial_movements_table.php

@@ -0,0 +1,40 @@
+<?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('financial_movements', function (Blueprint $table) {
+            $table->id();
+            $table->dateTime('date');
+            $table->foreignId('origin_id')->constrained('banks')->cascadeOnUpdate();
+            $table->foreignId('destination_id')->constrained('banks')->cascadeOnUpdate();
+            $table->decimal('amount', 12, 2);
+            $table->foreignId('causal_id')->constrained('causals')->cascadeOnUpdate();
+            $table->text('notes')->nullable();
+            $table->boolean('deleted')->default(false);
+            $table->timestamps();
+
+            $table->index(['date', 'origin_id', 'destination_id']);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('financial_movements');
+    }
+};

+ 9 - 2
resources/views/layouts/app.blade.php

@@ -212,6 +212,8 @@
                 print "Report presenze";
             if (Request::is('absence_reports'))
                 print "Assenze";
+            if (Request::is('financial_movements'))
+                print "Movimenti finanziari";
             @endphp
             </h3>
 
@@ -282,11 +284,11 @@
                         </div>
                         <div class="accordion-item">
                             <h2 class="accordion-header linkMenu" id="headingTwo">
-                                <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="{{Request::is('in') || Request::is('out') || Request::is('receipts') || Request::is('records_in_out') || Request::is('records') || Request::is('records_old') ? 'true' : 'false'}}" aria-controls="collapseTwo">
+                                <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="{{Request::is('in') || Request::is('out') || Request::is('receipts') || Request::is('records_in_out') || Request::is('records') || Request::is('records_old') || Request::is('financial_movements') ? 'true' : 'false'}}" aria-controls="collapseTwo">
                                     Contabilità
                                 </button>
                             </h2>
-                            <div id="collapseTwo" class="accordion-collapse collapse {{Request::is('in') || Request::is('out') || Request::is('receipts') || Request::is('records_in_out') || Request::is('records') || Request::is('records_old') ? 'show' : ''}}" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
+                            <div id="collapseTwo" class="accordion-collapse collapse {{Request::is('in') || Request::is('out') || Request::is('receipts') || Request::is('records_in_out') || Request::is('records') || Request::is('records_old') || Request::is('financial_movements') ? 'show' : ''}}" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
                                 <div class="accordion-body">
                                     <ul class="nav nav-pills flex-column align-items-center align-items-sm-start w-100" id="menu-contabilita" style="margin-top:0px;">
                                         <li class="nav-item" style="{{Request::is('in') ? 'background-color: #c5d9e6;' : ''}}">
@@ -323,6 +325,11 @@
                                                 <span class="ms-3 d-md-inline">Prima Nota (OLD)</span>
                                             </a>
                                         </li>
+                                        <li class="nav-item" style="{{Request::is('financial_movements') ? 'background-color: #c5d9e6;' : ''}}">
+                                            <a href="/financial_movements" class="nav-link d-flex align-items-center linkMenu">
+                                                <span class="ms-3 d-md-inline">Movimenti finanziari</span>
+                                            </a>
+                                        </li>
                                     </ul>
                                 </div>
                             </div>

+ 637 - 0
resources/views/livewire/financial_movements.blade.php

@@ -0,0 +1,637 @@
+<div class="col card--ui" id="card--dashboard">
+
+        <header id="title--section" style="display:none !important"  class="d-flex align-items-center justify-content-between">
+            <div class="title--section_name d-flex align-items-center justify-content-between">
+                <i class="ico--ui title_section entrate me-2"></i>
+                <h2 class="primary">@if(!$add && !$update)Movimenti finanziari @else Inserimento/modifica movimento @endif</h2>
+            </div>
+
+            @if(!$add && !$update)
+                <div class="title--section_addButton" wire:click="add()" style="cursor: pointer;">
+                    <div class="btn--ui entrata d-flex justify-items-between">
+                        <a href="#" wire:click="add()" style="color:white">Aggiungi</a>
+                    </div>
+                </div>
+            @endif
+
+        </header>
+
+    @if(!$add && !$update)
+
+        @if (session()->has('receipt'))
+            <div class="alert alert-success" role="alert">
+                {{ session()->get('receipt') }}
+            </div>
+        @endif
+
+        <div class="showFilter" style="display:none">
+            <hr size="1">
+            <div class="row g-3">
+                <div class="col-md-3">
+                    <div class="row">
+                        <div class="col-md-12" style="margin-bottom:10px;"><b>Data</b></div>
+                        <div class="col-12 mb-2">
+                            <input id="dateFrom" type="date" class="form-control filterFrom">
+                        </div>
+                        <div class="col-12">
+                            <input id="dateTo" type="date" class="form-control filterTo">
+                        </div>
+                        <div class="col-6 mt-2">
+                            <button class="btn--ui lightGrey todayButton" style="width:100%" onclick="setToday('{{date("Y-m-d")}}')">OGGI</button>
+                        </div>
+                        <div class="col-6 mt-2">
+                            <button class="btn--ui lightGrey yesterdayButton" style="width:100%" onclick="setYesterday('{{date("Y-m-d",strtotime("-1 days"))}}')">IERI</button>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-md-3">
+                    <div class="row">
+                        <div class="col-md-12" style="margin-bottom:10px;">
+                            <b>Origine</b>
+                        </div>
+                        <div class="col-12">
+                            <select name="search_origin_id" class="form-select filterOrigins" multiple="multiple">
+                                @foreach($origins as $origin)
+                                    <option value="{{$origin->id}}">{{$origin->name}}
+                                @endforeach
+                            </select>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-md-3">
+                    <div class="row">
+                        <div class="col-md-12" style="margin-bottom:10px;">
+                            <b>Destinazione</b>
+                        </div>
+                        <div class="col-12">
+                            <select name="search_destination_id" class="form-select filterDestinations" multiple="multiple">
+                                @foreach($destinations as $destination)
+                                    <option value="{{$destination->id}}">{{$destination->name}}
+                                @endforeach
+                            </select>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-md-3" style="text-align:right">
+                    <button class="btn--ui lightGrey" onclick="reset()">Reset</button>
+                    <button class="btn--ui" onclick="loadDataTable()">Filtra</button>
+                </div>
+            </div>
+            <hr size="1">
+        </div>
+
+        <section id="resume-table">
+            <table class="table tablesaw tableHead tablesaw-stack table--lista_movimenti tableHead" id="tablesaw-350" width="100%">
+                <thead>
+                    <tr>
+                        <!--<th scope="col"></th>-->
+                        <th scope="col">Data di pagamento</th>
+                        <th scope="col">Importo</th>
+                        <th scope="col">Origine</th>
+                        <th scope="col">Destinazione</th>
+                        <th scope="col">Causale</th>
+                        <th scope="col">...</th>
+                    </tr>
+                </thead>
+
+                <tbody id="checkall-target"></tbody>
+            </table>
+
+            <br><b class="totalDiv"></b>
+
+        </section>
+
+    @else
+
+        @if($isDuplicate)
+            <a style="margin-top:20px" class="btn--ui lightGrey" wire:click="cancel()" href="javascript:;"><i class="fa-solid fa-arrow-left"></i></a><br><br>
+        @else
+            <a style="margin-top:20px" class="btn--ui lightGrey" href="/financial_movements"><i class="fa-solid fa-arrow-left"></i></a><br><br>
+        @endif
+
+        <a name="top"></a>
+        @if (session()->has('error'))
+            <div class="alert alert-danger" role="alert">
+                {{ session()->get('error') }}
+            </div>
+        @endif
+
+        <section id="accountingEntry" class="d-flex">
+            <div class="accountingEntry_data" wire:key='reload-{{$dataId}}'>
+                <div class="form--accounting" >
+
+                    <div class="row gx-2">
+                        <div class="col-md-6">
+                            <span class="title-form d-block w-100">Data pagamento</span>
+                            <div class="input-group mb-3">
+                                <input id="date" type="date" class="form-control" wire:model="date">
+                            </div>
+                        </div>
+
+                    </div>
+
+                    <div class="row gx-2 mt-3">
+                        <div class="col-md-6" >
+                            <span class="title-form d-block w-100">Origine</span>
+                            <select class="form-select  @error('origin_id') is-invalid @enderror" aria-label="Seleziona un'origine" wire:model="origin_id" style="width:100%">
+                                <option value="">--Seleziona--</option>
+                                @foreach($origins as $origin)
+                                    <option value="{{$origin->id}}">{{$origin->name}}</option>
+                                @endforeach
+                            </select>
+                            @error('origin_id')
+                                <div class="invalid-feedback">{{ $message }}</div>
+                            @enderror
+                        </div>
+
+                        <div class="col-md-6" >
+                            <span class="title-form d-block w-100">Destinazione</span>
+                            <select class="form-select  @error('destination_id') is-invalid @enderror" aria-label="Seleziona una destinazione" wire:model="destination_id" style="width:100%">
+                                <option value="">--Seleziona--</option>
+                                @foreach($destinations as $destination)
+                                    <option value="{{$destination->id}}">{{$destination->name}}</option>
+                                @endforeach
+                            </select>
+                            @error('destination_id')
+                                <div class="invalid-feedback">{{ $message }}</div>
+                            @enderror
+                        </div>
+                    </div>
+
+                    <div class="row gx-2 mt-3">
+                        <div class="col-md-6" >
+                            <span class="title-form d-block w-100">Causale</span>
+                            <input class="form-control" id="causal" type="text" placeholder="Causale" wire:model="causal_name" disabled>
+                        </div>
+
+                        <div class="col-md-6" >
+                            <span class="title-form d-block w-100">Importo</span>
+                            <input type="text" class="form-control totalInput text-end @error('amount') is-invalid @enderror" id="amountFormatted" wire:model="amountFormatted" onkeyup="formatEuro(this)" placeholder="€ 0,00">
+                            @error('amount')
+                                <div class="invalid-feedback">{{ $message }}</div>
+                            @enderror
+                        </div>
+                    </div>
+
+                    <div class="row gx-2 mt-3">
+                        <div class="col-md-12">
+                            <span class="title-form d-block w-100">Note</span>
+                            <input type="text" class="form-control @error('notes') is-invalid @enderror" id="notes" wire:model="notes">
+                            @error('notes')
+                                <div class="invalid-feedback">{{ $message }}</div>
+                            @enderror
+                        </div>
+                    </div>
+
+
+                    <div class="accountingEntry--btn d-flex align-items-center justify-content-between mt-5">
+                        @if($isDuplicate)
+                            <button class="btn--ui lightGrey" wire:click="cancel()">annulla</button>
+                        @else
+                            <button class="btn--ui lightGrey" onclick="annulla()">annulla</button>
+                        @endif
+
+                        @if($add)
+                            <button class="btn--ui primary d-flex ms-auto" wire:click.prevent="store()"><span>Inserisci movimento</span></button>
+                        @endif
+                        @if($update)
+                            <button class="btn--ui primary d-flex ms-auto" wire:click.prevent="update()"><span>Aggiorna movimento</span></button>
+                        @endif
+                    </div>
+                </div>
+            </div>
+        </section>
+
+    @endif
+</div>
+
+@push('scripts')
+    <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
+    <style>
+        [for="dt-search-0"],
+        #dt-search-0 {
+            display: none;
+        }
+        table.tableHead thead {
+        /* Important */
+            position: sticky;
+            z-index: 100;
+            top: 0;
+        }
+        .select2-container--default .select2-selection--single{
+            background-color: #E9F0F5;
+            border: 0.0625rem solid #DFE5EB;
+            font-size: 0.75rem;
+        }
+        .select2-selection
+        {
+            height: 38px !important;
+        }
+        .select2-selection__rendered
+        {
+            padding-top:3px;
+        }
+        .select2 {
+            width:100% !important;
+        }
+        .page-link.active, .active > .page-link {
+            background-color:#006099 !important;
+        }
+
+        .select2-selection--multiple{
+            overflow: hidden !important;
+            height: auto !important;
+        }
+        .select2-container {
+            box-sizing: border-box;
+            display: inline-block;
+            margin: 0;
+            position: relative;
+            vertical-align: middle;
+        }
+        .select2-container .select2-selection--single {
+            box-sizing: border-box;
+            cursor: pointer;
+            display: block;
+            height: 38px;
+            user-select: none;
+            -webkit-user-select: none;
+        }
+        .select2-container .select2-selection--single .select2-selection__rendered {
+            display: block;
+            padding-left: 8px;
+            padding-right: 20px;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+        }
+        table.tablesaw tbody tr td.numericCol {
+            padding-right: 20px;
+        }
+    </style>
+    <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
+    <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
+@endpush
+
+@push('scripts')
+    <script>
+
+        function formatResult(node) {
+            var output = node.text.split(/[,-]+/).pop();
+            var $result = $('<span style="padding-left:' + (20 * (node.text.match(/-/g) || []).length) + 'px;">' + output + '</span>');
+            return $result;
+        };
+
+        function matchStart(params, data) {
+            params.term = params.term || '';
+            if (data.text.toUpperCase().indexOf(params.term.toUpperCase()) == 0) {
+                return data;
+            }
+            return false;
+        }
+
+        $(document).ready(function(){
+
+            $(document).on("keypress", $('.filterOrigins'), function (e) {
+                setTimeout(() => {
+                    $(".select2-results__option").each(function(){
+                        var txt = $(this).html();
+                        var count = (txt.match(/-/g) || []).length;
+                        $(this).addClass('paddingLeftSelect' + count);
+                    });
+                }, 100);
+            });
+
+            $(document).on("keypress", $('.filterDestinations'), function (e) {
+                setTimeout(() => {
+                    $(".select2-results__option").each(function(){
+                        var txt = $(this).html();
+                        var count = (txt.match(/-/g) || []).length;
+                        $(this).addClass('paddingLeftSelect' + count);
+                    });
+                }, 100);
+            });
+
+        });
+
+        Livewire.on('load-select', () => {
+            $('.filterOrigins').select2({"language": {"noResults": function(){return "Nessun risultato";}}});
+            $('.filterOrigins').on('change', function (e) {});
+            $('.filterDestinations').select2({"language": {"noResults": function(){return "Nessun risultato";}}});
+            $('.filterDestinations').on('change', function (e) {});
+        });
+
+        $('.filterOrigins').select2({"language": {"noResults": function(){return "Nessun risultato";}}});
+        $('.filterOrigins').on('change', function (e) {});
+        $('.filterDestinations').select2({"language": {"noResults": function(){return "Nessun risultato";}}});
+        $('.filterDestinations').on('change', function (e) {});
+
+        window.livewire.on('saved', () => {
+            $('#userModal').modal('hide');
+        });
+
+        function formatEuro(input) {
+            let v = input.value.replace(/\D+/g, '');
+            if (!v) {
+                input.value = '';
+                return;
+            }
+
+            input.value = "€ " + v.replace(/(\d)(\d\d)$/, "$1,$2").replace(/(^\d{1,3}|\d{3})(?=(?:\d{3})+(?:,|$))/g, '$1.');
+        }
+
+    </script>
+
+    <link href="/css/datatables.css" rel="stylesheet" />
+    <script src="/assets/js/datatables.js"></script>
+    <script src="https://cdn.datatables.net/buttons/3.0.2/js/buttons.dataTables.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js"></script>
+    <script>
+
+        $(document).ready(function() {
+            loadDataTable();
+
+            setTimeout(() => {
+                var h = $("#card--dashboard").height();
+            }, 500);
+        });
+
+        @if(isset($_GET["showFilters"]))
+            var filterOrigins = localStorage.getItem("filterOriginsFinancialMovements");
+            if (filterOrigins && filterOrigins != "null" && filterOrigins != "undefined")
+            {
+                $('.filterOrigins').val(filterOrigins);
+                $('.filterOrigins').trigger('change');
+            }
+            var filterDestinations = localStorage.getItem("filterDestinationsFinancialMovements");
+            if (filterDestinations && filterDestinations != "null" && filterDestinations != "undefined")
+            {
+                $('.filterDestinations').val(filterDestinations);
+                $('.filterDestinations').trigger('change');
+            }
+            var filterFrom = localStorage.getItem("filterFromFinancialMovements");
+            if (filterFrom && filterFrom != "null" && filterFrom != "undefined")
+            {
+                $('.filterFrom').val(filterFrom);
+            }
+            var filterTo = localStorage.getItem("filterToFinancialMovements");
+            if (filterTo && filterTo != "null" && filterTo != "undefined")
+            {
+                $('.filterTo').val(filterTo);
+            }
+        @endif
+
+        var isFilter = false;
+        $(document).ready(function() {
+            $(document).on("click",".showHideFilter",function() {
+                if (isFilter)
+                {
+                    isFilter = false;
+                    $(".showFilter").hide();
+                }
+                else
+                {
+                    isFilter = true;
+                    $(".showFilter").show();
+                }
+            });
+
+            $(document).on("select2:open",".filterOrigins",function() {
+                setTimeout(() => {
+                    $(".select2-results__option").each(function(){
+                        var txt = $(this).html();
+                        var count = (txt.match(/-/g) || []).length;
+                        $(this).addClass('paddingLeftSelect' + count);
+                    });
+                }, 100);
+            });
+            $(document).on("select2:open",".filterDestinations",function() {
+                setTimeout(() => {
+                    $(".select2-results__option").each(function(){
+                        var txt = $(this).html();
+                        var count = (txt.match(/-/g) || []).length;
+                        $(this).addClass('paddingLeftSelect' + count);
+                    });
+                }, 100);
+            });
+
+        } );
+
+        function editData(id)
+        {
+            @this.edit(id);
+        }
+
+        function duplicateData(id)
+        {
+            @this.duplicate(id);
+        }
+
+        function deleteData(id)
+        {
+            if (confirm('Sei sicuro?'))
+                @this.delete(id);
+        }
+
+        Livewire.on('load-data-table', () => {
+            setTimeout(function() {loadDataTable()}, 100);
+
+        });
+
+        Livewire.on('destroy-data-table', () => {
+            $('#tablesaw-350').DataTable().destroy();
+        });
+
+        function destroyDataTable()
+        {
+            $('#tablesaw-350').DataTable().destroy();
+        }
+
+        function reset()
+        {
+            $(".todayButton").addClass("lightGrey");
+            $(".yesterdayButton").addClass("lightGrey");
+            $('.filterOrigins').val('');
+            $('.filterOrigins').trigger('change');
+            $('.filterDestinations').val('');
+            $('.filterDestinations').trigger('change');
+            $('.filterFrom').val('');
+            $('.filterTo').val('');
+
+            loadDataTable();
+        }
+
+
+        function loadDataTable(){
+
+            if ( $.fn.DataTable.isDataTable('#tablesaw-350') ) {
+                $('#tablesaw-350').DataTable().destroy();
+            }
+
+            var filterOrigins = $('.filterOrigins').val();
+            var filterDestinations = $('.filterDestinations').val();
+            var filterFrom = $('.filterFrom').val();
+            var filterTo = $('.filterTo').val();
+
+            localStorage.setItem("filterOriginsFinancialMovements", filterOrigins);
+            localStorage.setItem("filterDestinationsFinancialMovements", filterDestinations);
+            localStorage.setItem("filterFromFinancialMovements", filterFrom);
+            localStorage.setItem("filterToFinancialMovements", filterTo);
+
+            var totalString = "";
+            $('#tablesaw-350').DataTable({
+                serverSide: true,
+                processing: true,
+                ajax: {
+                    url : '/get_financial_movements?&filterOrigins=' + filterOrigins + '&filterDestinations=' + filterDestinations + '&filterFrom=' + filterFrom + '&filterTo=' + filterTo,
+                    dataSrc: function (json){
+                        if(json.totals){
+                            $(".totalDiv").html('Totale&nbsp;:&nbsp;<b>' + json.totals + '</b>');
+                        }
+                        else
+                        {
+                            $(".totalDiv").html('');
+                        }
+                        @if(Auth::user()->level != 0)
+                            $(".totalDiv").html('');
+                        @endif
+                        return json.data;
+                    }
+                },
+                columns: [
+                    // { data: 'id' },
+                    {
+                        data: "date",
+                        render: function (data, type){
+                            if (data == "") return " ";
+                            if (type == "sort"){
+                                return new Date(data).getTime();
+                            }
+                            const j = data.split(" ");
+                            const d = j[0].split("-");
+                            var ret = d[2] + "/" + d[1] + "/" + d[0];
+                            return ret;
+                        },
+                    },
+                    { data: 'total', className: "numericCol" },
+                    { data: 'origin' },
+                    { data: 'destination' },
+                    { data: 'causal', "orderable": false, },
+                    {
+                        data: "action",
+                        render: function (data){
+                            if (data == "")
+                                return "";
+                            const j = data.split("|");
+                            var ret = '';
+                            if (j[2] != 'x')
+                            {
+                                ret = '<button type="button" class="btn" onclick="editData(' + j[0] + ')" data-bs-toggle="popover"  data-bs-trigger="hover focus" data-bs-placement="bottom" data-bs-content="Modifica"><i class="fa-regular fa-pen-to-square"></i></button>&nbsp;';
+                                ret += '<button type="button" class="btn" onclick="deleteData(' + j[0] + ')"  data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-placement="bottom" data-bs-content="Elimina"><i class="fa-regular fa-trash-can"></i></button>';
+                                ret += '<button type="button" class="btn btn-outline-default btn-sm" onclick="duplicateData(' + j[0] + ')" data-bs-toggle="popover"  data-bs-trigger="hover focus" data-bs-placement="bottom" data-bs-content="Duplica"><i class="fa-regular fa-copy"></i></button>';
+                            }
+                            else
+                            {
+                                ret = '<button type="button" class="btn" onclick="editData(' + j[0] + ')" data-bs-toggle="popover"  data-bs-trigger="hover focus" data-bs-placement="bottom" data-bs-content="Visualizza"><i class="fa-regular fa-file"></i></button>&nbsp;';
+                            }
+                            return ret;
+                        }
+                    },
+                ],
+                fixedHeader: false,
+                order: [[0, 'desc']],
+                thead: {
+                'th': {'background-color': 'blue'}
+                },
+                layout: {
+                    topStart : null,
+                    topEnd : null,
+                    top1A: {
+                        buttons: [
+                            {
+                                extend: 'collection',
+                                text: 'ESPORTA',
+                                buttons: [
+                                    {
+                                    extend: 'excelHtml5',"action":newexportaction,
+                                        title: 'Movimenti finanziari',
+                                        exportOptions: {
+                                            columns: ":not(':last')"
+                                        }
+                                    },
+                                    {
+                                        extend: 'pdfHtml5',"action":newexportaction,
+                                        title: 'Movimenti finanziari',
+                                        exportOptions: {
+                                            columns: ":not(':last')"
+                                        }
+                                    },
+                                    {
+                                        extend: 'print',"action":newexportaction,
+                                        text: 'Stampa',
+                                        title: 'Movimenti finanziari',
+                                        exportOptions: {
+                                            columns: ":not(':last')"
+                                        }
+                                    }
+                                ],
+                                dropup: true
+                            }
+                        ]
+                    },
+                    top1B : {
+                        pageLength: {
+                            menu: [[10, 25, 50, 100, 100000], [10, 25, 50, 100, "Tutti"]]
+                        }
+                    },
+                    top1C :'search',
+                },
+                pagingType: 'numbers',
+                "language": {
+                    "url": "/assets/js/Italian.json"
+                },
+                "fnInitComplete": function (oSettings, json) {
+                    var html = '&nbsp;<a href="#" class="showHideFilter btn--ui"><i class="fa-solid fa-sliders"></i></a>';
+                    html += '&nbsp;<a  style="cursor:pointer" class="addData btn--ui"><i class="fa-solid fa-plus"></i></a>';
+                    $(".dt-search").append(html);
+                }
+            });
+            $('#tablesaw-350 thead tr th').addClass('col');
+            $('#tablesaw-350 thead tr th').css("background-color", "#f6f8fa");
+            $('#tablesaw-350').on('draw.dt', function() {
+                $('[data-bs-toggle="popover"]').popover()
+            });
+
+        }
+
+        $(document).ready(function() {
+            $(document).on("click",".addData",function() {
+                $(".title--section_addButton").trigger("click")
+            });
+        } );
+
+        var isEdit = false;
+        Livewire.on('setEdit', (x) =>
+        {
+            isEdit = x;
+        });
+
+        Livewire.on('reload', (x) =>
+        {
+            location.reload();
+        });
+
+        function annulla() {
+            window.onbeforeunload = null;
+            window.location.href = '/financial_movements';
+        }
+
+        window.onbeforeunload = function(){
+            if (isEdit)
+                return 'Cambiando pagina le eventuali modifiche andranno perse';
+        };
+    </script>
+
+@endpush

+ 13 - 10
resources/views/livewire/records.blade.php

@@ -386,17 +386,20 @@
                 @php $count = 0; @endphp
                 @foreach($records as $record)
                     @if($record->date != '')
+                        @php
+                            $bg = $count % 2 == 0 ? 'white' : '#f2f4f7';
+                        @endphp
                         <tr>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{date("d/m/Y", strtotime($record->date))}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{$record->commercial ? 'Commerciale' : 'Non commerciale'}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}; width: 22%;white-space: pre-line;">{{$record->causal_name}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}; width: 22%">{{$record->type == 'IN' ? ($record->member->first_name . " " . $record->member->last_name) : @$record->supplier->name}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{$record->deleted ? 'Annullata' : ''}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}; text-align: right; color: green">{{$record->type == 'IN' ? formatPrice($record->amount) : ''}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}; text-align: right; color: red">{{$record->type == 'OUT' ? formatPrice($record->amount) : ''}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}; padding-left: 20px;">{{$record->type == 'OUT' ? $record->origin : ''}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{$record->type == 'IN' ? $record->destination : ''}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{$record->payment_method->name}}</td>
+                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{ date("d/m/Y", strtotime($record->date)) }}</td>
+                            <td style="background-color: {{$bg}}">{{ in_array($record->type, ['MOVE_IN','MOVE_OUT']) ? '' : ($record->commercial ? 'Commerciale' : 'Non commerciale') }}</td>
+                            <td style="background-color: {{$bg}}; width:22%; white-space:pre-line;">{{ $record->causal_name }}</td>
+                            <td style="background-color: {{$bg}}; width:22%">@if($record->type === 'IN'){{ $record->member->first_name }} {{ $record->member->last_name }}@elseif($record->type === 'OUT'){{ @$record->supplier->name }}@endif</td>
+                            <td style="background-color: {{$bg}}">{{ $record->deleted ? 'Annullata' : '' }}</td>
+                            <td style="background-color: {{$bg}}; text-align:right; color:green">{{ in_array($record->type, ['IN','MOVE_IN']) ? formatPrice($record->amount) : '' }}</td>
+                            <td style="background-color: {{$bg}}; text-align:right; color:red">{{ in_array($record->type, ['OUT','MOVE_OUT']) ? formatPrice($record->amount) : '' }}</td>
+                            <td style="background-color: {{$bg}}; padding-left:20px;">{{ in_array($record->type, ['OUT','MOVE_OUT']) ? $record->origin : '' }}</td>
+                            <td style="background-color: {{$bg}}">{{ in_array($record->type, ['IN','MOVE_IN']) ? $record->destination : '' }}</td>
+                            <td style="background-color: {{$bg}}">{{ in_array($record->type, ['MOVE_IN','MOVE_OUT']) ? '' : $record->payment_method->name }}</td>
                         </tr>
                         @php $count++; @endphp
                     @endif

+ 188 - 100
routes/web.php

@@ -33,13 +33,11 @@ Route::get('/login', function () {
 
 Route::post('/login', function () {
 
-    if(Auth::attempt(array('email' => $_POST["email"], 'password' => $_POST["password"])))
-    {
+    if (Auth::attempt(array('email' => $_POST["email"], 'password' => $_POST["password"]))) {
         if (Auth::user()->level == ENV('INSTRUCTOR_LEVEL', 2))
             return Redirect::to('/calendar');
         else
             return Redirect::to('/dashboard');
-
     } else {
         return Redirect::to('/?error=1');
     }
@@ -97,6 +95,7 @@ Route::group(['middleware' => 'auth'], function () {
     Route::get('/motivations', \App\Http\Livewire\Motivation::class);
     Route::get('/reports', \App\Http\Livewire\Reports::class);
     Route::get('/members_archive', \App\Http\Livewire\MemberArchive::class);
+    Route::get('/financial_movements', \App\Http\Livewire\FinancialMovements::class);
 });
 
 Route::get('/receipt/{id}', function ($id) {
@@ -186,12 +185,12 @@ Route::get('/get_members', function () {
     // $datas = \App\Models\Member::select('members.*')->where('id', '>', 0);
     $x = \App\Models\Member::select('id', 'first_name', 'last_name', 'phone', 'birth_date', 'to_complete', 'current_status', 'certificate', 'certificate_date')
         ->where('id', '>', 0)
-        ->where(function($query) use($archived) {
+        ->where(function ($query) use ($archived) {
             $query->where('is_archived', $archived);
             if (!$archived)
                 $query->orWhereNull('is_archived');
         })
-        ->where(function($query) {
+        ->where(function ($query) {
             $query->where('is_deleted', false)
                 ->orWhereNull('is_deleted');
         });
@@ -302,12 +301,12 @@ Route::get('/get_members', function () {
                 $scadIds = $expiringMemberIds;
             } else if ($filterValue == "3") {
                 $scadIds = \App\Models\Member::whereNotIn('id', \App\Models\MemberCertificate::pluck('member_id'))
-                    ->where(function($query) use($archived) {
+                    ->where(function ($query) use ($archived) {
                         $query->where('is_archived', $archived);
                         if (!$archived)
                             $query->orWhereNull('is_archived');
                     })
-                    ->where(function($query) {
+                    ->where(function ($query) {
                         $query->where('is_deleted', false)
                             ->orWhereNull('is_deleted');
                     })
@@ -342,16 +341,16 @@ Route::get('/get_members', function () {
         $status = explode(",", $_GET["filterStatus"]);
         // $members = \App\Models\Member::all();
         // Only get non-archived members for status filtering
-        $members = \App\Models\Member::where(function($query) use($archived) {
-            $query->where(function($q) use($archived) {
+        $members = \App\Models\Member::where(function ($query) use ($archived) {
+            $query->where(function ($q) use ($archived) {
                 $q->where('is_archived', $archived);
                 if (!$archived)
                     $q->orWhereNull('is_archived');
             })
-            ->where(function($q) {
-                $q->where('is_deleted', false)
-                    ->orWhereNull('is_deleted');
-            });
+                ->where(function ($q) {
+                    $q->where('is_deleted', false)
+                        ->orWhereNull('is_deleted');
+                });
         })->get();
         foreach ($status as $s) {
             foreach ($members as $m) {
@@ -516,13 +515,13 @@ Route::get('/get_record_in', function () {
         ->leftJoin('receipts', 'records.id', '=', 'receipts.record_id')
         ->where('records.type', 'IN');
 
-        $x = \App\Models\Record::select('records.*', DB::raw('members.first_name as first_name'), DB::raw('members.last_name as last_name'), DB::raw('payment_methods.name as payment'), DB::raw('receipts.created_at as receipt_date')) // , \DB::raw('SUM(records.id) As total'))
-                ->leftJoin('members', 'records.member_id', '=', 'members.id')
-                ->leftJoin('payment_methods', 'records.payment_method_id', '=', 'payment_methods.id')
-                ->leftJoin('receipts', 'records.id', '=', 'receipts.record_id')
-                ->where('records.type', 'IN');
+    $x = \App\Models\Record::select('records.*', DB::raw('members.first_name as first_name'), DB::raw('members.last_name as last_name'), DB::raw('payment_methods.name as payment'), DB::raw('receipts.created_at as receipt_date')) // , \DB::raw('SUM(records.id) As total'))
+        ->leftJoin('members', 'records.member_id', '=', 'members.id')
+        ->leftJoin('payment_methods', 'records.payment_method_id', '=', 'payment_methods.id')
+        ->leftJoin('receipts', 'records.id', '=', 'receipts.record_id')
+        ->where('records.type', 'IN');
 
-        $y = \App\Models\Record::select('records_rows.record_id', 'records_rows.amount', 'records.member_id', 'records.corrispettivo_fiscale', 'records.commercial', 'records.deleted', 'records.financial_movement', 'records_rows.causal_id', 'records.payment_method_id', DB::raw('members.first_name as first_name'), DB::raw('members.last_name as last_name')) // , \DB::raw('SUM(records.id) As total'))
+    $y = \App\Models\Record::select('records_rows.record_id', 'records_rows.amount', 'records.member_id', 'records.corrispettivo_fiscale', 'records.commercial', 'records.deleted', 'records.financial_movement', 'records_rows.causal_id', 'records.payment_method_id', DB::raw('members.first_name as first_name'), DB::raw('members.last_name as last_name')) // , \DB::raw('SUM(records.id) As total'))
         ->leftJoin('members', 'records.member_id', '=', 'members.id')
         ->leftJoin('records_rows', 'records.id', '=', 'records_rows.record_id')
         //->leftJoin('receipts', 'records.id', '=', 'receipts.record_id')
@@ -633,8 +632,8 @@ Route::get('/get_record_in', function () {
         if ($borsellino)
             $excludeCausals[] = $borsellino->id;*/
 
-        // Aggiungo
-        /*
+    // Aggiungo
+    /*
         $excludes = \App\Models\Causal::where('no_records', true)->get();
         foreach($excludes as $e)
         {
@@ -642,11 +641,11 @@ Route::get('/get_record_in', function () {
         }*/
 
     $exclude_from_records = \App\Models\Member::where('exclude_from_records', true)
-        ->where(function($query) {
+        ->where(function ($query) {
             $query->where('is_archived', false)
                 ->orWhereNull('is_archived');
         })
-        ->where(function($query) {
+        ->where(function ($query) {
             $query->where('is_deleted', false)
                 ->orWhereNull('is_deleted');
         })->pluck('id')->toArray();
@@ -669,26 +668,26 @@ Route::get('/get_record_in', function () {
     foreach ($y->get() as $r) {
 
         if (!in_array($r->payment_method_id, $moneys)) {
-            
+
             if (
-                (!in_array($r->member_id, $exclude_from_records) || in_array($r->causal_id, $moneysCausal)) 
-                 && 
-                 (!$r->deleted || $r->deleted == null) 
-                 && 
-                 (!in_array($r->causal_id, $excludeCausals) || in_array($r->causal_id, $moneysCausal)) 
-                 && 
-                 (!$r->financial_movement || $r->financial_movement == null) 
-                 && 
-                 (!$r->corrispettivo_fiscale || $r->corrispettivo_fiscale == null)
-                 ) {
-            //    if (sizeof($causals) == 0 || in_array($r->causal_id, $causals)) {
-                    $total += $r->amount;
-                    if ($r->vat_id > 0)
-                        $total += getVatValue($r->amount, $r->vat_id);
-
-                    //$aIds[] = array('id' => $r->record_id, 'amount' => $r->amount);
-                    $aIds[] = $r->record_id;
-            //    }
+                (!in_array($r->member_id, $exclude_from_records) || in_array($r->causal_id, $moneysCausal))
+                &&
+                (!$r->deleted || $r->deleted == null)
+                &&
+                (!in_array($r->causal_id, $excludeCausals) || in_array($r->causal_id, $moneysCausal))
+                &&
+                (!$r->financial_movement || $r->financial_movement == null)
+                &&
+                (!$r->corrispettivo_fiscale || $r->corrispettivo_fiscale == null)
+            ) {
+                //    if (sizeof($causals) == 0 || in_array($r->causal_id, $causals)) {
+                $total += $r->amount;
+                if ($r->vat_id > 0)
+                    $total += getVatValue($r->amount, $r->vat_id);
+
+                //$aIds[] = array('id' => $r->record_id, 'amount' => $r->amount);
+                $aIds[] = $r->record_id;
+                //    }
             }
         }
 
@@ -696,7 +695,7 @@ Route::get('/get_record_in', function () {
     }
     //print $count;
     //print implode(",",$aIds);
-    
+
     $count = $x->count();
 
     if (isset($_GET["order"])) {
@@ -868,6 +867,105 @@ Route::get('/get_record_out', function () {
         return json_encode(array("data" => $datas));
 });
 
+Route::get('/get_financial_movements', function () {
+    $filterFrom = request('filterFrom');
+    $filterTo = request('filterTo');
+    $filterOrigins = request('filterOrigins');
+    $filterDestinations = request('filterDestinations');
+
+    $base = \App\Models\FinancialMovement::query()
+        ->leftJoin('banks as origins', 'origins.id', '=', 'financial_movements.origin_id')
+        ->leftJoin('banks as destinations', 'destinations.id', '=', 'financial_movements.destination_id')
+        ->leftJoin('causals as causals', 'causals.id', '=', 'financial_movements.causal_id')
+        ->where('financial_movements.deleted', false);
+
+    if (!empty($filterFrom)) {
+        $base->whereDate('financial_movements.date', '>=', $filterFrom);
+    }
+
+    if (!empty($filterTo)) {
+        $base->whereDate('financial_movements.date', '<=', $filterTo);
+    }
+
+    if ($filterOrigins && $filterOrigins !== "null") {
+        $origins = array_filter(explode(",", $filterOrigins));
+        if (!empty($origins)) {
+            $base->whereIn('financial_movements.origin_id', $origins);
+        }
+    }
+
+    if ($filterDestinations && $filterDestinations !== "null") {
+        $destinations = array_filter(explode(",", $filterDestinations));
+        if (!empty($destinations)) {
+            $base->whereIn('financial_movements.destination_id', $destinations);
+        }
+    }
+
+    $recordsFiltered = (clone $base)->count();
+
+    $recordsTotal = \App\Models\FinancialMovement::where('deleted', false)->count();
+
+    $totalAmount = (clone $base)->sum('financial_movements.amount');
+
+    $start = (int) request('start', 0);
+    $limit = (int) request('length', 100000);
+
+    $order = request('order');
+    if ($order) {
+        $colIdx = (int) ($order[0]['column'] ?? 0);
+        $dir = ($order[0]['dir'] ?? 'desc') === 'asc' ? 'asc' : 'desc';
+
+        $column = match ($colIdx) {
+            0 => 'financial_movements.date',
+            1 => 'financial_movements.amount',
+            2 => 'origins.name',
+            3 => 'destinations.name',
+            default => 'financial_movements.id',
+        };
+
+        $base->orderBy($column, $dir)->orderBy('financial_movements.id', 'DESC');
+    } else {
+        $base->orderBy('financial_movements.date', 'DESC')->orderBy('financial_movements.id', 'DESC');
+    }
+
+    $rows = $base
+        ->select([
+            'financial_movements.id',
+            'financial_movements.date',
+            'financial_movements.amount',
+            'financial_movements.deleted',
+            'origins.name as origin_name',
+            'destinations.name as destination_name',
+            'causals.name as causal_name',
+        ])
+        ->offset($start)
+        ->limit($limit)
+        ->get();
+
+    $data = [];
+    foreach ($rows as $r) {
+        $data[] = [
+            'id' => $r->id,
+            'date' => $r->date,
+            'origin' => $r->origin_name ?? '',
+            'destination' => $r->destination_name ?? '',
+            'total' => formatPrice($r->amount),
+            'causal' => $r->causal_name ?? '',
+            'action' => $r->id . "|0|" . ($r->deleted ? 'x' : '')
+        ];
+    }
+
+    $draw = (int) request('draw', 0);
+
+    return response()->json([
+        "draw" => $draw,
+        "data" => $data,
+        "recordsTotal" => $recordsTotal,
+        "recordsFiltered" => $recordsFiltered,
+        "totals" => formatPrice($totalAmount),
+    ]);
+});
+
 Route::get('/get_course_list', function () {
 
     $member_course = \App\Models\MemberCourse::with('member')->with('course');
@@ -877,14 +975,14 @@ Route::get('/get_course_list', function () {
         if ($_GET["search"]["value"] != '') {
             $v = str_replace("'", "\'", stripcslashes($_GET["search"]["value"]));
             $member_ids = \App\Models\Member::where(function ($query) use ($v) {
-                    $query->whereRaw("CONCAT(first_name, ' ', last_name) like '%" . $v . "%'")
-                        ->orWhereRaw("CONCAT(last_name, ' ', first_name) like '%" . $v . "%'");
-                })
-                ->where(function($query) {
+                $query->whereRaw("CONCAT(first_name, ' ', last_name) like '%" . $v . "%'")
+                    ->orWhereRaw("CONCAT(last_name, ' ', first_name) like '%" . $v . "%'");
+            })
+                ->where(function ($query) {
                     $query->where('is_archived', false)
                         ->orWhereNull('is_archived');
                 })
-                ->where(function($query) {
+                ->where(function ($query) {
                     $query->where('is_deleted', false)
                         ->orWhereNull('is_deleted');
                 })->pluck('id');
@@ -1252,7 +1350,7 @@ Route::get('/get_course_members', function () {
 
     //$datas = \App\Models\MemberCourse::with('member');
 
-    $datas = \App\Models\MemberCourse::select('member_courses.*', 'courses.name as course_name', 'members.first_name', 'members.last_name', 'members.email', 'members.phone', 'members.birth_date','members.gender')
+    $datas = \App\Models\MemberCourse::select('member_courses.*', 'courses.name as course_name', 'members.first_name', 'members.last_name', 'members.email', 'members.phone', 'members.birth_date', 'members.gender')
         ->leftJoin('courses', 'member_courses.course_id', '=', 'courses.id')
         ->leftJoin('members', 'member_courses.member_id', '=', 'members.id');
 
@@ -1260,14 +1358,14 @@ Route::get('/get_course_members', function () {
         $v = str_replace("'", "\'", stripcslashes($_GET["search"]["value"]));
 
         $member_ids = \App\Models\Member::where(function ($query) use ($v) {
-                $query->whereRaw("CONCAT(first_name, ' ', last_name) like '%" . $v . "%'")
-                    ->orWhereRaw("CONCAT(last_name, ' ', first_name) like '%" . $v . "%'");
-            })
-            ->where(function($query) {
+            $query->whereRaw("CONCAT(first_name, ' ', last_name) like '%" . $v . "%'")
+                ->orWhereRaw("CONCAT(last_name, ' ', first_name) like '%" . $v . "%'");
+        })
+            ->where(function ($query) {
                 $query->where('is_archived', false)
                     ->orWhereNull('is_archived');
             })
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_deleted', false)
                     ->orWhereNull('is_deleted');
             })->pluck('id');
@@ -1279,8 +1377,7 @@ Route::get('/get_course_members', function () {
         $datas = $datas->whereIn('member_id', $member_ids);
     }
 
-    if (isset($_GET["filterFromPrevious"]) && $_GET["filterFromPrevious"] != "")
-    {
+    if (isset($_GET["filterFromPrevious"]) && $_GET["filterFromPrevious"] != "") {
         $datas = $datas->whereIn('course_id', [$_GET["filterFromPrevious"]]);
     }
 
@@ -1384,11 +1481,11 @@ Route::get('/get_course_members', function () {
                 $allScadIds = array_merge($allScadIds, $expiringMemberIds);
             } else if ($filterValue == "3") {
                 $scadIds = \App\Models\Member::whereNotIn('id', \App\Models\MemberCertificate::pluck('member_id'))
-                    ->where(function($query) {
+                    ->where(function ($query) {
                         $query->where('is_archived', false)
                             ->orWhereNull('is_archived');
                     })
-                    ->where(function($query) {
+                    ->where(function ($query) {
                         $query->where('is_deleted', false)
                             ->orWhereNull('is_deleted');
                     })
@@ -1424,11 +1521,11 @@ Route::get('/get_course_members', function () {
 
     if ($_GET["fromYear"] != "") {
         $m_ids = \App\Models\Member::where('birth_date', '<', date("Y-m-d", strtotime("-" . $_GET["fromYear"] . " year", time())))
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_archived', false)
                     ->orWhereNull('is_archived');
             })
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_deleted', false)
                     ->orWhereNull('is_deleted');
             })->pluck('id');
@@ -1437,11 +1534,11 @@ Route::get('/get_course_members', function () {
 
     if ($_GET["toYear"] != "") {
         $m_ids = \App\Models\Member::where('birth_date', '>', date("Y-m-d", strtotime("-" . $_GET["toYear"] . " year", time())))
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_archived', false)
                     ->orWhereNull('is_archived');
             })
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_deleted', false)
                     ->orWhereNull('is_deleted');
             })->pluck('id');
@@ -1450,11 +1547,11 @@ Route::get('/get_course_members', function () {
 
     if ($_GET["fromFromYear"] != "") {
         $m_ids = \App\Models\Member::whereYear('birth_date', '>=', $_GET["fromFromYear"])
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_archived', false)
                     ->orWhereNull('is_archived');
             })
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_deleted', false)
                     ->orWhereNull('is_deleted');
             })->pluck('id');
@@ -1462,11 +1559,11 @@ Route::get('/get_course_members', function () {
     }
     if ($_GET["toToYear"] != "") {
         $m_ids = \App\Models\Member::whereYear('birth_date', '<=', $_GET["toToYear"])
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_archived', false)
                     ->orWhereNull('is_archived');
             })
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_deleted', false)
                     ->orWhereNull('is_deleted');
             })->pluck('id');
@@ -1561,7 +1658,7 @@ Route::get('/get_course_members', function () {
             $genderDisplay = "Donna";
         } elseif ($r->gender == 'O') {
             $genderDisplay = "Altro";
-        }elseif ($r->gender == null || $r->gender == "") {
+        } elseif ($r->gender == null || $r->gender == "") {
             $genderDisplay = "N/A";
         }
 
@@ -1592,14 +1689,14 @@ Route::get('/get_receipts', function () {
     if (isset($_GET["search"]["value"]) && !empty($_GET["search"]["value"])) {
         $v = str_replace("'", "\'", stripcslashes($_GET["search"]["value"]));
         $member_ids = \App\Models\Member::where(function ($query) use ($v) {
-                $query->whereRaw("CONCAT(first_name, ' ', last_name) like '%" . $v . "%'")
-                    ->orWhereRaw("CONCAT(last_name, ' ', first_name) like '%" . $v . "%'");
-            })
-            ->where(function($query) {
+            $query->whereRaw("CONCAT(first_name, ' ', last_name) like '%" . $v . "%'")
+                ->orWhereRaw("CONCAT(last_name, ' ', first_name) like '%" . $v . "%'");
+        })
+            ->where(function ($query) {
                 $query->where('is_archived', false)
                     ->orWhereNull('is_archived');
             })
-            ->where(function($query) {
+            ->where(function ($query) {
                 $query->where('is_deleted', false)
                     ->orWhereNull('is_deleted');
             })->pluck('id');
@@ -1623,16 +1720,16 @@ Route::get('/get_receipts', function () {
     $receiptIds = $baseQuery->pluck('receipts.id');
 
     $dataQuery = \App\Models\Receipt::select(
-            'receipts.id',
-            'receipts.year',
-            'receipts.number',
-            'receipts.status',
-            'receipts.created_at',
-            'receipts.record_id',
-            'members.first_name',
-            'members.last_name',
-            DB::raw('SUM(receipts_rows.amount) AS totals')
-        )
+        'receipts.id',
+        'receipts.year',
+        'receipts.number',
+        'receipts.status',
+        'receipts.created_at',
+        'receipts.record_id',
+        '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')
         ->whereIn('receipts.id', $receiptIds)
@@ -1720,7 +1817,7 @@ function getColor($months, $m)
     return $class;
 }
 
-Route::get('/migrate', function(){
+Route::get('/migrate', function () {
     Artisan::call('migrate');
     dd('migrated!');
 });
@@ -1763,8 +1860,7 @@ Route::get('/send_sms', function () {
     $certificates = \App\Models\MemberCertificate::where('expire_date', $expire_date)->get();
     foreach ($certificates as $certificate) {
         $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->where('member_id', $certificate->member_id)->count();
-        if ($new == 0)
-        {
+        if ($new == 0) {
             $phone = $certificate->member->phone;
             $message = 'Ciao ' . $certificate->member->first_name . ', ci risulta che il tuo certificato medico scade il ' . $expire_date_it . '. Per continuare ad allenarti senza problemi, ricordati di rinnovarlo in tempo. Ti aspettiamo in campo! Centro Sportivo La Madonnella';
             $params = array(
@@ -1785,8 +1881,7 @@ Route::get('/send_sms', function () {
     $certificates = \App\Models\MemberCertificate::where('expire_date', $expire_date)->get();
     foreach ($certificates as $certificate) {
         $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->where('member_id', $certificate->member_id)->count();
-        if ($new == 0)
-        {
+        if ($new == 0) {
             $phone = $certificate->member->phone;
             $message = 'Ciao ' . $certificate->member->first_name . ', ci risulta che il tuo certificato medico scade il ' . $expire_date_it . '. Per continuare ad allenarti senza problemi, ricordati di rinnovarlo in tempo. Ti aspettiamo in campo! Centro Sportivo La Madonnella';
             $params = array(
@@ -1801,31 +1896,24 @@ Route::get('/send_sms', function () {
             sleep(1);
         }
     }
-
 });
 
 Route::get('/fix', function () {
     $datas = \App\Models\MemberCourse::whereNotNull('date_from')->get();
-    foreach($datas as $data)
-    {
+    foreach ($datas as $data) {
         $data->date_from = date("Y-m-d", strtotime($data->created_at));
         $date_to = '';
         $months = json_decode($data->months);
-        foreach($months as $m)
-        {
-            if ($m->m >= 9)
-            {
+        foreach ($months as $m) {
+            if ($m->m >= 9) {
                 $check = "2025-" . $m->m . "-01";
                 $date_to = date("Y-m-t", strtotime($check));
-            }
-            else
-            {
+            } else {
                 $check = "2026-" . $m->m . "-01";
                 $date_to = date("Y-m-t", strtotime($check));
             }
         }
         $data->date_to = $date_to;
         $data->save();
-        
-    }    
-});
+    }
+});