Просмотр исходного кода

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

Luca Parisio 1 месяц назад
Родитель
Сommit
088b279748

+ 2 - 2
app/Console/Commands/SendSms.php

@@ -32,7 +32,7 @@ class SendSms extends Command
         $expire_date_it = date("d/m/Y", strtotime("+1 month"));
         $certificates = \App\Models\MemberCertificate::where('expire_date', $expire_date)->get();
         foreach ($certificates as $certificate) {            
-            $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->count();
+            $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->where('member_id', $certificate->member_id)->count();
             if ($new == 0)
             {
                 $phone = $certificate->member->phone;
@@ -51,7 +51,7 @@ class SendSms extends Command
         $expire_date_it = date("d/m/Y", strtotime("+15 days"));
         $certificates = \App\Models\MemberCertificate::where('expire_date', $expire_date)->get();
         foreach ($certificates as $certificate) {
-            $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->count();
+            $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->where('member_id', $certificate->member_id)->count();
             if ($new == 0)
             {
                 $phone = $certificate->member->phone;

+ 332 - 46
app/Http/Livewire/AbsenceReport.php

@@ -2,88 +2,374 @@
 
 namespace App\Http\Livewire;
 
+use Illuminate\Support\Carbon;
 use Livewire\Component;
 
 class AbsenceReport extends Component
 {
 
     public $records;
+    public $record_assenze;
+    public $original_record_assenze;
 
+    public $fiscalStartMonth = 9;
     public $year;
 
+    public $search;
+
     public function mount()
     {
         setlocale(LC_ALL, 'it_IT');
+
+        $this->record_assenze = [];
+
+        $end_day = now()->yesterday();
+        $limit = $end_day->endOfDay();
+
+        $this->year = ($end_day->month >= $this->fiscalStartMonth) ? $end_day->year : $end_day->year - 1;
+
+        $dayMap = [
+            'lun' => 1,
+            'mar' => 2,
+            'mer' => 3,
+            'gio' => 4,
+            'ven' => 5,
+            'sab' => 6,
+            'dom' => 0,
+        ];
+
+        try {
+            $courses = \App\Models\Course::whereDate('date_from', '<=', $limit)
+                ->whereDate('date_to', '>=', $limit)
+                ->where('active', true)
+                ->where('enabled', true)
+                ->get();
+
+            foreach ($courses as $course) {
+                $course_members = \App\Models\MemberCourse::with(['member' => function ($q) {
+                    $q->where(function ($q) {
+                        $q->where('is_archived', false)->orWhereNull('is_archived');
+                    })->where(function ($q) {
+                        $q->where('is_deleted', false)->orWhereNull('is_deleted');
+                    });
+                }])
+                    ->where('course_id', $course->id)
+                    ->whereHas('member', function ($q) {
+                        $q->where(function ($q) {
+                            $q->where('is_archived', false)->orWhereNull('is_archived');
+                        })->where(function ($q) {
+                            $q->where('is_deleted', false)->orWhereNull('is_deleted');
+                        });
+                    })
+                    ->get();
+
+                $courseCalendars = \App\Models\Calendar::where('course_id', $course->id)->where('from', '<=', $limit)->where('status', '<>', 99)->get();
+
+                $calendarIndex = [];
+                foreach ($courseCalendars as $cal) {
+                    $fromKey = Carbon::parse($cal->from)->toDateTimeString();
+                    $toKey = Carbon::parse($cal->to)->toDateTimeString();
+                    $key = $fromKey . '|' . $toKey;
+
+                    $calendarIndex[$key] = $cal;
+                }
+
+                $memberIds = $course_members->pluck('member_id')->unique()->values();
+
+                $makeups = \App\Models\Presence::query()
+                    ->join('calendars', 'presences.calendar_id', '=', 'calendars.id')
+                    ->where('presences.motivation_course_id', $course->id)
+                    ->whereIn('presences.member_id', $memberIds)
+                    ->where('presences.status', '<>', 99)
+                    ->where('calendars.from', '<=', $limit)
+                    ->where('calendars.status', '<>', 99)
+                    ->selectRaw('presences.member_id, MAX(calendars.from) as last_makeup_from')
+                    ->groupBy('presences.member_id')
+                    ->get();
+
+                $lastMakeupByMember = [];
+                foreach ($makeups as $m) {
+                    $lastMakeupByMember[$m->member_id] = Carbon::parse($m->last_makeup_from);
+                }
+
+                $this->record_assenze[$course->id] = [
+                    'course' => [
+                        'id' => $course->id,
+                        'name' => $course->getDetailsName(),
+                    ],
+                    'members' => [],
+                ];
+
+                foreach ($course_members as $course_member) {
+                    $this->record_assenze[$course->id]['members'][$course_member->id] = [
+                        'member' => [
+                            'id' => $course_member->member->id,
+                            'first_name' => $course_member->member->first_name,
+                            'last_name' => $course_member->member->last_name,
+                        ],
+                        'count'  => 0,
+                        'dates'  => [],
+                    ];
+
+                    $months = array_column(
+                        array_filter(json_decode($course_member->months, true), fn($m) => $m['status'] != 2),
+                        'm'
+                    );
+                    sort($months);
+
+                    $when = json_decode($course_member->when, true);
+
+                    $memberCalendars = [];
+
+                    foreach ($when as $period) {
+                        $days = $period['day'];
+
+                        if (!$days) {
+                            continue;
+                        }
+
+                        $fromTime = $period['from'];
+                        $toTime   = $period['to'];
+
+                        $ranges = $this->generateFiscalDateRanges($months, $days, $dayMap, $fromTime, $toTime);
+
+                        foreach ($ranges as $range) {
+                            $key = $range['from']->toDateTimeString() . '|' . $range['to']->toDateTimeString();
+
+                            if (isset($calendarIndex[$key])) {
+                                $memberCalendars[] = $calendarIndex[$key];
+                            }
+                        }
+                    }
+
+                    usort($memberCalendars, fn($a, $b) => $b->to <=> $a->to);
+
+                    $mid = $course_member->member_id;
+                    $lastAttendance = $lastMakeupByMember[$mid] ?? null;
+                    foreach ($memberCalendars as $calendar) {
+                        $lessonFrom = Carbon::parse($calendar->from);
+
+                        if ($lastAttendance && $lessonFrom->lte($lastAttendance)) {
+                            break;
+                        }
+
+                        $pKey = $mid . '|' . $calendar->id;
+                        $hasPresence = isset($presenceIndex[$pKey]);
+
+                        if ($hasPresence) {
+                            break;
+                        }
+
+                        // assenza vera
+                        $this->record_assenze[$course->id]['members'][$course_member->id]['count']++;
+                        $this->record_assenze[$course->id]['members'][$course_member->id]['dates'][] = [
+                            'calendar_id' => $calendar->id,
+                            'date' => $lessonFrom->translatedFormat('d/m'),
+                        ];
+                    }
+
+                    if ($this->record_assenze[$course->id]['members'][$course_member->id]['count'] < 2) {
+                        unset($this->record_assenze[$course->id]['members'][$course_member->id]);
+                    }
+                }
+
+                if (empty($this->record_assenze[$course->id]['members'])) {
+                    unset($this->record_assenze[$course->id]);
+                } else {
+                    $members = $this->record_assenze[$course->id]['members'];
+                    usort($members, function ($a, $b) {
+                        if ($a['count'] !== $b['count']) {
+                            return $b['count'] <=> $a['count'];
+                        }
+
+                        $last = strcmp($a['member']['last_name'], $b['member']['last_name']);
+                        if ($last !== 0) {
+                            return $last;
+                        }
+
+                        return strcmp($a['member']['first_name'], $b['member']['first_name']);
+                    });
+                    $this->record_assenze[$course->id]['members'] = $members;
+                }
+            }
+
+            usort($this->record_assenze, fn($a, $b) => $a['course']['name'] <=> $b['course']['name']);
+        } catch (\Throwable $e) {
+            dd($e->getMessage());
+        }
+
+        $this->original_record_assenze = $this->record_assenze;
     }
 
     public function render()
     {
         setlocale(LC_ALL, 'it_IT');
 
-        $this->records = [];
+        // $this->records = [];
 
         // $to = date("Y-m-d 23:59:59");
         // $calendars = \App\Models\Calendar::where('from', '<=', $to)->orderBy('from')->get();
 
-        $month = date("n");
-        $this->year = ($month >= 9) ? date("Y") : date("Y") - 1;
+        // $month = date("n");
+        // $this->year = ($month >= 9) ? date("Y") : date("Y") - 1;
 
-        $start = date("Y-m-d H:i:s", mktime(0, 0, 0, 9, 1, $this->year));
-        $end   = date("Y-m-d 23:59:59");
+        // $start = date("Y-m-d H:i:s", mktime(0, 0, 0, 9, 1, $this->year));
+        // $end   = date("Y-m-d 23:59:59");
 
-        $calendars = \App\Models\Calendar::whereBetween('from', [$start, $end])->orderBy('from')->get();
+        // $calendars = \App\Models\Calendar::whereBetween('from', [$start, $end])->orderBy('from')->get();
 
-        foreach ($calendars as $calendar) {
+        // foreach ($calendars as $calendar) {
 
-            $presences = \App\Models\Presence::where('calendar_id', $calendar->id)->where('status', '<>', 99);
-            $presences = $presences->pluck('member_id')->toArray();
-            $presences_annullate = \App\Models\Presence::where('calendar_id', $calendar->id)->where('status', 99)->pluck('member_id')->toArray();
+        //     $presences = \App\Models\Presence::where('calendar_id', $calendar->id)->where('status', '<>', 99);
+        //     $presences = $presences->pluck('member_id')->toArray();
+        //     $presences_annullate = \App\Models\Presence::where('calendar_id', $calendar->id)->where('status', 99)->pluck('member_id')->toArray();
 
-            $days = ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'];
-            $dow = date('w', strtotime($calendar->from));
-            $d = $days[$dow];
+        //     $days = ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'];
+        //     $dow = date('w', strtotime($calendar->from));
+        //     $d = $days[$dow];
 
-            $h = date('H:i', strtotime($calendar->from));
+        //     $h = date('H:i', strtotime($calendar->from));
 
-            // Elenco corsi per tipologia in base al calendario
-            $courses = \App\Models\Course::where('name', $calendar->name)->where('date_from', '<=', $calendar->from)->where('date_to', '>=', $calendar->to);
-            $courses = $courses->pluck('id')->toArray();
+        //     // Elenco corsi per tipologia in base al calendario
+        //     $courses = \App\Models\Course::where('name', $calendar->name)->where('date_from', '<=', $calendar->from)->where('date_to', '>=', $calendar->to);
+        //     $courses = $courses->pluck('id')->toArray();
 
-            $months = date("n", strtotime($calendar->from));
+        //     $months = date("n", strtotime($calendar->from));
 
-            // Elenco utenti iscritti al corso "padre"
-            $members = \App\Models\MemberCourse::where('when', 'like', "%" . $d . "%")
-                ->where('when', 'like', '%"from":"' . $h . '"%')
-                ->whereNot('months', 'like', '%"m":' . $months . ',"status":2%')
-                ->whereDate('date_from', '<=', $calendar->from)                                 
-                ->whereDate('date_to', '>=', $calendar->from)      
-                ->whereIn('course_id', $courses)
-                ->orderBy('member_id')
-                ->get();
-            //$members = \App\Models\MemberCourse::where('when', 'like', "%" . $d . "%")->where('when', 'like', '%"from":"' . $h . '"%')->whereIn('member_id', $presences)->whereIn('course_id', $courses)->get();
-            foreach ($members as $member) {
-
-                $presence = \App\Models\Presence::where('member_id', $member->member->id)->where('calendar_id', $calendar->id)->first();
-
-                if (!in_array($member->member->id, $presences)) {
-                    if (!in_array($member->member->id, $presences_annullate)) {
-                        if (array_key_exists($member->member->id, $this->records)) {
-                            $this->records[$member->member->id]['total'] += 1;
-                            $this->records[$member->member->id]['date'] .= " - " . date("d/m", strtotime($calendar->from));
-                        } else
-                            $this->records[$member->member->id] = array("last_name" => $member->member->last_name, "first_name" => $member->member->first_name, "course" => $calendar->name, "total" => 1, "date" => date("d/m", strtotime($calendar->from)));
+        //     // Elenco utenti iscritti al corso "padre"
+        //     $members = \App\Models\MemberCourse::where('when', 'like', "%" . $d . "%")
+        //         ->where('when', 'like', '%"from":"' . $h . '"%')
+        //         ->whereNot('months', 'like', '%"m":' . $months . ',"status":2%')
+        //         ->whereDate('date_from', '<=', $calendar->from)
+        //         ->whereDate('date_to', '>=', $calendar->from)
+        //         ->whereIn('course_id', $courses)
+        //         ->orderBy('member_id')
+        //         ->get();
+        //     //$members = \App\Models\MemberCourse::where('when', 'like', "%" . $d . "%")->where('when', 'like', '%"from":"' . $h . '"%')->whereIn('member_id', $presences)->whereIn('course_id', $courses)->get();
+        //     foreach ($members as $member) {
+
+        //         $presence = \App\Models\Presence::where('member_id', $member->member->id)->where('calendar_id', $calendar->id)->first();
+
+        //         if (!in_array($member->member->id, $presences)) {
+        //             if (!in_array($member->member->id, $presences_annullate)) {
+        //                 if (array_key_exists($member->member->id, $this->records)) {
+        //                     $this->records[$member->member->id]['total'] += 1;
+        //                     $this->records[$member->member->id]['date'] .= " - " . date("d/m", strtotime($calendar->from));
+        //                 } else
+        //                     $this->records[$member->member->id] = array("last_name" => $member->member->last_name, "first_name" => $member->member->first_name, "course" => $calendar->name, "total" => 1, "date" => date("d/m", strtotime($calendar->from)));
+        //             }
+        //         } else {
+        //             if (array_key_exists($member->member->id, $this->records))
+        //                 unset($this->records[$member->member->id]);
+        //         }
+        //     }
+        // }
+
+        // array_multisort(array_column($this->records, 'total'), SORT_DESC, $this->records);
+
+        return view('livewire.absence_report');
+    }
+
+    public function applySearch()
+    {
+        $this->search = trim($this->search);
+        $this->filter();
+    }
+
+    public function resetSearch()
+    {
+        $this->search = '';
+        $this->record_assenze = $this->original_record_assenze;
+    }
+
+    protected function filter()
+    {
+        $this->record_assenze = $this->original_record_assenze;
+
+        if ($this->search === '') return;
+
+        $needle = mb_strtolower($this->search);
+
+        foreach ($this->record_assenze as $courseId => $courseData) {
+            $courseData['members'] = array_values(array_filter($courseData['members'], function ($m) use ($needle) {
+                $full  = mb_strtolower((trim($m['member']['last_name']) ?? '') . ' ' . (trim($m['member']['first_name']) ?? ''));
+                $full2 = mb_strtolower((trim($m['member']['first_name']) ?? '') . ' ' . (trim($m['member']['last_name']) ?? ''));
+                return str_contains($full, $needle) || str_contains($full2, $needle);
+            }));
+
+            if (empty($courseData['members'])) {
+                unset($this->record_assenze[$courseId]);
+            } else {
+                $this->record_assenze[$courseId] = $courseData;
+            }
+        }
+    }
+
+    protected function generateFiscalDateRanges($months, $days, $dayMap, $fromTime, $toTime)
+    {
+        $limit = now()->yesterday()->endOfDay();
+
+        $end_day = $limit;
+
+        $startYear = ($end_day->month >= $this->fiscalStartMonth) ? $end_day->year : $end_day->year - 1;
+
+        $allowedDow = collect($days)
+            ->map(fn($d) => $dayMap[$d] ?? null)
+            ->filter(fn($v) => $v !== null)
+            ->unique()
+            ->values();
+
+        $fromCarbon = Carbon::parse($fromTime);
+        $toCarbon = Carbon::parse($toTime);
+
+        $fromHour = $fromCarbon->hour;
+        $fromMinute = $fromCarbon->minute;
+        $fromSecond = $fromCarbon->second;
+
+        $toHour = $toCarbon->hour;
+        $toMinute = $toCarbon->minute;
+        $toSecond = $toCarbon->second;
+
+        $ranges = [];
+
+        foreach ($months as $month) {
+            $yearForMonth = ($month >= $this->fiscalStartMonth)
+                ? $startYear
+                : $startYear + 1;
+
+            if (
+                $yearForMonth > $limit->year ||
+                ($yearForMonth === $limit->year && $month > $limit->month)
+            ) {
+                continue;
+            }
+
+            $firstOfMonth = Carbon::create($yearForMonth, $month, 1)->startOfDay();
+
+            foreach ($allowedDow as $dow) {
+                $offset  = ($dow - $firstOfMonth->dayOfWeek + 7) % 7;
+                $current = $firstOfMonth->copy()->addDays($offset);
+
+                while ($current->month === $month) {
+                    $fromDateTime = $current->copy()->setTime($fromHour, $fromMinute, $fromSecond);
+                    $toDateTime   = $current->copy()->setTime($toHour, $toMinute, $toSecond);
+
+                    if ($fromDateTime->gt($limit)) {
+                        break;
                     }
-                }
-                else
-                {
-                    if (array_key_exists($member->member->id, $this->records))
-                        unset($this->records[$member->member->id]);
+
+                    $ranges[] = [
+                        'from' => $fromDateTime,
+                        'to'   => $toDateTime,
+                    ];
+
+                    $current->addWeek();
                 }
             }
         }
 
-        array_multisort(array_column($this->records, 'total'), SORT_DESC, $this->records);
+        usort($ranges, fn($a, $b) => $a['from'] <=> $b['from']);
 
-        return view('livewire.absence_report');
+        return $ranges;
     }
 }

+ 307 - 324
app/Http/Livewire/Member.php

@@ -49,14 +49,14 @@ class Member extends Component
         if ($type === 'corsi' && $this->dataId > 0) {
             $this->loadMemberCards();
             $this->checkCourseAvailability();
-        }        
+        }
         if ($type === 'presenze') {
             //$this->emit('load-chart', $this->mesi, $this->valori);
             //if (sizeof($this->mesi) == 0 && sizeof($this->valori) == 0)
-                $this->loadMemberPresences();
+            $this->loadMemberPresences();
             //else
             //    $this->emit('load-chart', $this->mesi, $this->valori);
-        }        
+        }
         $this->dispatchBrowserEvent('scroll-to-top');
     }
     public function sortBy($field)
@@ -162,6 +162,9 @@ class Member extends Component
     public $presenceTitleFilter = '';
     public $member_presences = [];
 
+    public $presenceCourses = [];
+    public $presenceCourseFilter = '';
+
     public $totals = 0;
     public $presenze = 0;
     public $assenze = 0;
@@ -302,16 +305,6 @@ class Member extends Component
         $this->image_old = '';
     }
 
-    public function updatedPresenceYearFilter()
-    {
-        $this->loadMemberPresences();   
-    }
-
-    public function updatedPresenceTitleFilter()
-    {
-        $this->loadMemberPresences();   
-    }
-
     public function updatedCourseName()
     {
         $this->course_course_id = null;
@@ -383,7 +376,6 @@ class Member extends Component
                 $this->course_course_id = $course->id;
                 $this->course_price = formatPrice($course->price);
                 $this->course_subscription_price = formatPrice($course->subscription_price);
-
             } else {
                 $this->course_price = 0;
                 $this->course_subscription_price = 0;
@@ -530,8 +522,6 @@ class Member extends Component
             $this->festivita[] = $pasqua;     // Domenica di Pasqua
             $this->festivita[] = $pasquetta;  // Lunedì dell'Angelo
         }
-
-
     }
 
     public function updated()
@@ -650,10 +640,10 @@ class Member extends Component
 
 
         $datas = [];
-        
+
         $this->loadMemberCards();
         $this->loadMemberCourses();
-        
+
         $this->loadMemberCategories();
         $this->loadMemberCertificates();
 
@@ -686,12 +676,12 @@ class Member extends Component
         $this->member_courses = \App\Models\MemberCourse::where('member_id', $this->dataId)->get();
 
         if ($this->dataId) {
-            $order = [9,10,11,12,1,2,3,4,5,6,7,8];
+            $order = [9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8];
 
-            $this->member_courses = $this->member_courses->map(function($course) use ($order) {
+            $this->member_courses = $this->member_courses->map(function ($course) use ($order) {
                 $months = json_decode($course->months, true);
 
-                usort($months, function($a, $b) use ($order) {
+                usort($months, function ($a, $b) use ($order) {
                     $posA = array_search($a['m'], $order);
                     $posB = array_search($b['m'], $order);
                     return $posA <=> $posB;
@@ -715,263 +705,266 @@ class Member extends Component
         // return view('livewire.member');
     }
 
-    public function loadMemberPresences()
+    public function updatedPresenceYearFilter()
+    {
+        $this->presenceCourseFilter = '';
+        $this->loadPresenceCombos();
+        $this->loadMemberPresences();
+    }
+
+    public function updatedPresenceCourseFilter()
+    {
+        $this->loadMemberPresences();
+    }
+
+    public function loadPresenceCombos()
     {
+        $this->presenceYears = [];
+        $this->presenceCourses = [];
 
-        $this->mesi = array('Settembre', 'Ottobre', 'Novembre', 'Dicembre', 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto');
-        $this->valori = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        if (!$this->dataId) {
+            $this->presenceYearFilter = '';
+            $this->presenceCourseFilter = '';
+            return;
+        }
 
-        $this->loadCombo();
+        $subscribedCourseIds = \App\Models\MemberCourse::where('member_id', $this->dataId)
+            ->pluck('course_id')
+            ->all();
 
-        $this->member_presences = [];
+        $makeupCourseIds = \App\Models\Presence::where('member_id', $this->dataId)
+            ->where('status', '<>', 99)
+            ->whereNotNull('motivation_course_id')
+            ->pluck('motivation_course_id')
+            ->all();
 
-        // Carico tutti i calendar_id delle presenza
-        $presences = \App\Models\Presence::where('member_id', $this->dataId)->where('status', '<>', 99)->pluck('calendar_id')->toArray();
-        $presences_annullate = \App\Models\Presence::where('member_id', $this->dataId)->where('status', 99)->pluck('calendar_id')->toArray();
+        $allCourseIds = array_values(array_unique(array_merge($subscribedCourseIds, $makeupCourseIds)));
+
+        if (!empty($allCourseIds)) {
+            $this->presenceYears = \App\Models\Course::whereIn('id', $allCourseIds)
+                ->orderBy('year', 'desc')
+                ->groupBy('year')
+                ->pluck('year')
+                ->map(fn($y) => (string)$y)
+                ->all();
+        }
 
-        $course_ids = array();
-        
-        // Tutti i calendari
-        if ($this->presenceYearFilter == '' && sizeof($this->presenceYears) > 0)
+        if (($this->presenceYearFilter === '' || !in_array((string)$this->presenceYearFilter, $this->presenceYears, true)) && !empty($this->presenceYears)) {
             $this->presenceYearFilter = $this->presenceYears[0];
+        }
 
-        if ($this->presenceTitleFilter == '' && sizeof($this->presenceTitle) > 0)
-            $this->presenceTitleFilter = $this->presenceTitle[0];
+        if ($this->presenceYearFilter !== '' && !empty($allCourseIds)) {
+            $this->presenceCourses = \App\Models\Course::whereIn('id', $allCourseIds)
+                ->where('year', $this->presenceYearFilter)
+                ->orderBy('name')
+                ->get(['id', 'name', 'year', 'course_level_id', 'course_type_id', 'course_frequency_id']);
+        }
 
-        $curses_ids = \App\Models\Course::where('year', $this->presenceYearFilter)->pluck('id')->toArray();
+        $validCourseIds = collect($this->presenceCourses)->pluck('id')->map(fn($id) => (string)$id)->all();
+        if (($this->presenceCourseFilter === '' || !in_array((string)$this->presenceCourseFilter, $validCourseIds, true)) && !empty($validCourseIds)) {
+            $this->presenceCourseFilter = $validCourseIds[0];
+        }
+    }
 
-        $calendars = \App\Models\Calendar::whereNull('manual')->whereIn('course_id', $curses_ids)->where('name', $this->presenceTitleFilter)->orderBy('from')->get();
+    public function loadMemberPresences()
+    {
+        $this->mesi = ['Settembre', 'Ottobre', 'Novembre', 'Dicembre', 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto'];
+        $this->valori = array_fill(0, 12, 0);
+
+        $monthMap = [9 => 0, 10 => 1, 11 => 2, 12 => 3, 1 => 4, 2 => 5, 3 => 6, 4 => 7, 5 => 8, 6 => 9, 7 => 10, 8 => 11];
 
+        // reset output
+        $this->member_presences = [];
         $this->totals = 0;
         $this->presenze = 0;
         $this->assenze = 0;
         $this->annullate = 0;
         $this->recuperi = [];
 
-        define("PRESENZE", 0);
-        define("ASSENZE", 1);
-        // define("RECUPERO", 2);
-        define("ANNULLATE", 2);
+        $this->loadPresenceCombos();
+
+        if (!$this->dataId || $this->presenceYearFilter === '' || $this->presenceCourseFilter === '') {
+            $this->emit('load-chart', $this->mesi, $this->valori, []);
+            return;
+        }
+
+        $courseId = (int)$this->presenceCourseFilter;
 
         $chartData = [
-            PRESENZE => [
-                "label" => "Presenze",
-                "backgroundColor" => "#0c6197",
-                "data" => array_fill(0, 12, 0),
-                "grouped" => true,
-                "stack" => "chartData",
-                "barThickness" => "flex",
-                "barPercentage" => 0.5,
-                "categoryPercentage" => 0.3,
-            ],
-            ASSENZE => [
-                "label" => "Assenze",
-                "backgroundColor" => "#ff0000",
-                "data" => array_fill(0, 12, 0),
-                "grouped" => true,
-                "stack" => "chartData",
-                "barThickness" => "flex",
-                "barPercentage" => 0.5,
-                "categoryPercentage" => 0.3,
-                
-            ],
-            // RECUPERO => [
-            //     "label" => "Recupero",
-            //     "backgroundColor" => "#7136f6",
-            //     "data" => array_fill(0, 12, 0),
-            //     "grouped" => true,
-            //     "stack" => "chartData",
-            //     "barThickness" => "flex",
-            //     "barPercentage" => 0.5,
-            //     "categoryPercentage" => 0.3,
-            // ],
-            ANNULLATE => [
-                "label" => "Annullate",
-                "backgroundColor" => "#808080",
-                "data" => array_fill(0, 12, 0),
-                "grouped" => true,
-                "stack" => "chartData",
-                "barThickness" => "flex",
-                "barPercentage" => 0.5,
-                "categoryPercentage" => 0.3,
-                
-            ],
-        ];
-        $monthMap = [
-            9 => 0,
-            10 => 1,
-            11 => 2,
-            12 => 3,
-            1 => 4,
-            2 => 5,
-            3 => 6,
-            4 => 7,
-            5 => 8,
-            6 => 9,
-            7 => 10,
-            8 => 11,
+            0 => ["label" => "Presenze", "backgroundColor" => "#0c6197", "data" => array_fill(0, 12, 0), "grouped" => true, "stack" => "chartData", "barThickness" => "flex", "barPercentage" => 0.5, "categoryPercentage" => 0.3],
+            1 => ["label" => "Assenze", "backgroundColor" => "#ff0000", "data" => array_fill(0, 12, 0), "grouped" => true, "stack" => "chartData", "barThickness" => "flex", "barPercentage" => 0.5, "categoryPercentage" => 0.3],
+            2 => ["label" => "Annullate", "backgroundColor" => "#808080", "data" => array_fill(0, 12, 0), "grouped" => true, "stack" => "chartData", "barThickness" => "flex", "barPercentage" => 0.5, "categoryPercentage" => 0.3],
         ];
 
-        foreach($calendars as $calendar)
-        {
-            
-            $days = ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'];
-            $dow = date('w', strtotime($calendar->from));
-            $d = $days[$dow];
+        $calendars = \App\Models\Calendar::whereNull('manual')
+            ->where('course_id', $courseId)
+            ->orderBy('from')
+            ->get(['id', 'from', 'to', 'status']);
+
+        $calendarIds = $calendars->pluck('id')->all();
+
+        $presencesByCalendar = [];
+        if (!empty($calendarIds)) {
+            $presencesByCalendar = \App\Models\Presence::where('member_id', $this->dataId)
+                ->whereIn('calendar_id', $calendarIds)
+                ->with('motivation:id,name,show_in_member_presences')
+                ->get(['calendar_id', 'status', 'motivation_id'])
+                ->keyBy('calendar_id')
+                ->all();
+        }
+
+        $memberCourse = \App\Models\MemberCourse::where('member_id', $this->dataId)
+            ->where('course_id', $courseId)
+            ->first();
+
+        $expected = null;
+
+        if ($memberCourse) {
+            $months = json_decode($memberCourse->months, true) ?: [];
+            $monthAllowed = [];
+            foreach ($months as $m) {
+                $mm = (int)($m['m'] ?? 0);
+                $st = (string)($m['status'] ?? '');
+                if ($mm >= 1 && $mm <= 12 && $st !== '2') {
+                    $monthAllowed[$mm] = true;
+                }
+            }
 
-            $h = date('H:i', strtotime($calendar->from));
+            $when = json_decode($memberCourse->when, true) ?: [];
+            $allowedSlots = [];
+            foreach ($when as $period) {
+                $days = $period['day'] ?? [];
+                $from = $period['from'] ?? null;
+                if (!$from || empty($days)) continue;
+                $hhmm = substr($from, 0, 5);
+                foreach ($days as $d) {
+                    $allowedSlots[$d . '|' . $hhmm] = true;
+                }
+            }
 
-            // Elenco corsi per tipologia in base al calendario
-            $courses = \App\Models\Course::where('name', $calendar->name)->where('date_from', '<=', $calendar->from)->where('date_to', '>=', $calendar->to)->pluck('id')->toArray();
+            $expected = [
+                'date_from' => $memberCourse->date_from,
+                'date_to'   => $memberCourse->date_to,
+                'monthAllowed' => $monthAllowed,
+                'allowedSlots' => $allowedSlots,
+            ];
+        }
 
-            $months = date("n", strtotime($calendar->from));
+        $isExpected = function (string $calendarFrom) use ($expected) {
+            if (!$expected) return false;
 
-            // Elenco utenti iscritti al corso "padre"
-            if (\App\Models\MemberCourse::where('when', 'like', "%" . $d . "%")->where('when', 'like', '%"from":"' . $h . '"%')->whereNot('months', 'like', '%"m":' . $months . ',"status":2%')->whereDate('date_from', '<=', $calendar->from)->whereDate('date_to', '>=', $calendar->from)->where('months', 'like', '%"m":' . $months . ',%')->whereIn('course_id', $courses)->where('member_id', $this->dataId)->first())
-            {
-                $status = '';
-                $annullata = false;
-                $motivation = null;
-                if (in_array($calendar->id, $presences))
-                {
-                    $status = "<span style=\"color:#0c6197\">Presenza</span>";
-                    $this->presenze += 1;
-                    $this->valori[$monthMap[date('n', strtotime($calendar->from))]] += 1;
-                    $chartData[PRESENZE]["data"][$monthMap[date('n', strtotime($calendar->from))]] += 1;
-
-                    $presence = \App\Models\Presence::where('member_id', $this->dataId)->where('status', '<>', 99)->where('calendar_id', $calendar->id)->first();
-                    if ($presence->motivation && $presence->motivation->show_in_member_presences) {
-                        $motivation = $presence->motivation->name;
-                        if (!isset($this->recuperi[$motivation])) $this->recuperi[$motivation] = 0;
+            if ($calendarFrom < $expected['date_from'] || $calendarFrom > $expected['date_to']) return false;
 
-                        $this->recuperi[$motivation] += 1;
-                    }
-                }
-                else
-                {
-                    if (in_array($calendar->id, $presences_annullate))
-                    {
-                        $status = "<span style=\"color:gray\">Annullata</span>";
-                        $this->annullate += 1;
-
-                        $chartData[ANNULLATE]["data"][$monthMap[date('n', strtotime($calendar->from))]] += 1;
-                        $annullata = true;
-                    }
-                    else
-                    {
-                        if (date("Ymd") > date("Ymd", strtotime($calendar->from)))
-                        {
-                            $status = "<span style=\"color:red\">Assenza</span>";
-                            $this->assenze += 1;
+            $days = ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'];
+            $dow = (int)date('w', strtotime($calendarFrom));
+            $d = $days[$dow];
+            $h = date('H:i', strtotime($calendarFrom));
+            $m = (int)date('n', strtotime($calendarFrom));
 
-                            $chartData[ASSENZE]["data"][$monthMap[date('n', strtotime($calendar->from))]] += 1;
-                        }
-                    }
-                }
+            if (empty($expected['monthAllowed'][$m])) return false;
+            if (empty($expected['allowedSlots'][$d . '|' . $h])) return false;
 
-                if ($calendar->status == 99 && !$annullata)
-                {
-                    $status = "<span style=\"color:gray\">Annullata</span>";
-                    $this->annullate += 1;
+            return true;
+        };
 
-                    $chartData[ANNULLATE]["data"][$monthMap[date('n', strtotime($calendar->from))]] += 1;
-                }
-                
-                $this->member_presences[] = array('calendar_id' => $calendar->id, 'from' => $calendar->from, 'to' => $calendar->to, 'status' => $status, 'motivation' => $motivation);//\App\Models\Presence::where('member_id', $this->dataId)->get();
-            }
+        if ($expected) {
+            foreach ($calendars as $calendar) {
+                if (!$isExpected($calendar->from)) continue;
 
-            //$courses = array(1);
-            foreach($courses as $c)
-            {
-                $course_ids[] = $c;    
-            }
+                $idxMonth = $monthMap[(int)date('n', strtotime($calendar->from))] ?? null;
 
-            //$course_ids = array_push($course_ids, $courses);
+                $presence = $presencesByCalendar[$calendar->id] ?? null;
 
-        }
+                $calendarCancelled = ((int)$calendar->status === 99);
+                $presenceCancelled = ($presence && (int)$presence->status === 99);
+
+                $statusHtml = '';
+                $motivationName = null;
 
-        // Manuali (recuperi)
-        // $calendar_recuperi = \App\Models\Calendar::where('manual', 1)->where('name', $this->presenceTitleFilter)->pluck('id')->toArray();
-        $calendar_recuperi = \App\Models\Calendar::where('manual', 1)->where('name', $this->presenceTitleFilter)->pluck('id')->toArray();
-        $presences_recuperi = \App\Models\Presence::whereIn('calendar_id', $calendar_recuperi)->where('member_id', $this->dataId)->get();
-        foreach($presences_recuperi as $p)
-        {
-            if ($p->motivation && $p->motivation->show_in_member_presences) {
-                // $this->member_presences[] = array('calendar_id' => $p->calendar->id, 'from' => $p->calendar->from, 'to' => $p->calendar->to, 'status' => '<span style="color:#7136f6">Recupero</span>', 'motivation' => $p->motivation->name);//\App\Models\Presence::where('member_id', $this->dataId)->get();
-                $this->member_presences[] = array('calendar_id' => $p->calendar->id, 'from' => $p->calendar->from, 'to' => $p->calendar->to, 'status' => '<span style=\"color:#0c6197\">Presenza</span>', 'motivation' => $p->motivation->name);//\App\Models\Presence::where('member_id', $this->dataId)->get();
+                if ($calendarCancelled || $presenceCancelled) {
+                    $statusHtml = "<span style=\"color:gray\">Annullata</span>";
+                    $this->annullate++;
+                    if ($idxMonth !== null) $chartData[2]['data'][$idxMonth]++;
+                } elseif ($presence) {
+                    $statusHtml = "<span style=\"color:#0c6197\">Presenza</span>";
+                    $this->presenze++;
+                    if ($idxMonth !== null) {
+                        $this->valori[$idxMonth]++;
+                        $chartData[0]['data'][$idxMonth]++;
+                    }
 
-                if (!isset($this->recuperi[$p->motivation->name])) $this->recuperi[$p->motivation->name] = 0;
+                    if ($presence->motivation && $presence->motivation->show_in_member_presences) {
+                        $motivationName = ucfirst($presence->motivation->name);
+                        $this->recuperi[$motivationName] = ($this->recuperi[$motivationName] ?? 0) + 1;
+                    }
+                } else {
+                    if (date('Ymd') > date('Ymd', strtotime($calendar->from))) {
+                        $statusHtml = "<span style=\"color:red\">Assenza</span>";
+                        $this->assenze++;
+                        if ($idxMonth !== null) $chartData[1]['data'][$idxMonth]++;
+                    } else {
+                        $statusHtml = "";
+                    }
+                }
 
-                $this->recuperi[$p->motivation->name] += 1;
-                $this->presenze += 1;
-                
-                // $chartData[RECUPERO]["data"][$monthMap[date('n', strtotime($p->calendar->from))]] += 1;
-                $chartData[PRESENZE]["data"][$monthMap[date('n', strtotime($p->calendar->from))]] += 1;
+                $this->member_presences[] = [
+                    'calendar_id' => $calendar->id,
+                    'from' => $calendar->from,
+                    'to'   => $calendar->to,
+                    'status' => $statusHtml,
+                    'motivation' => $motivationName,
+                ];
             }
         }
 
-        $sortVariable='from';
-        usort(
-            $this->member_presences, 
-            fn(array $a, array $b): int => $a[$sortVariable] <=> $b[$sortVariable]
-        );
+        $makeups = \App\Models\Presence::where('member_id', $this->dataId)
+            ->where('status', '<>', 99)
+            ->where('motivation_course_id', $courseId)
+            ->with([
+                'calendar:id,from,to,status',
+                'motivation:id,name,show_in_member_presences',
+            ])
+            ->get(['calendar_id', 'status', 'motivation_id', 'motivation_course_id']);
 
-        
-        $this->emit('load-chart', $this->mesi, $this->valori, $chartData);
+        $alreadyCalendar = array_flip(array_column($this->member_presences, 'calendar_id'));
 
-        //usort($this->member_presences, $this->cmp);
-        //usort($this->member_presences, function ($a, $b) { return $a['from'] > $b['from']; });
-        
-        //$this->presenceYears = \App\Models\Course::whereIn('id', $course_ids)->orderBy('year')->groupBy('year')->pluck('year')->toArray();
-        //if (sizeof($this->presenceYears) > 0)
-        //    $this->presenceYearFilter = $this->presenceYears[0];
-        //$this->presenceTitle = \App\Models\Course::whereIn('id', $course_ids)->orderBy('name')->groupBy('name')->pluck('name')->toArray();
+        foreach ($makeups as $p) {
+            if (!$p->calendar) continue;
 
-        
-        // return view('livewire.member');
-    }
+            if (isset($alreadyCalendar[$p->calendar_id])) continue;
 
-    public function loadCombo()
-    {
-        $course_ids = array();
-        
-        //$calendars = \App\Models\Calendar::whereNull('manual')->orderBy('from')->get();
+            if (!$p->motivation || !$p->motivation->show_in_member_presences) continue;
 
-        /*
-        foreach($calendars as $calendar)
-        {
-  
-            $days = ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'];
-            $dow = date('w', strtotime($calendar->from));
-            $d = $days[$dow];
+            $idxMonth = $monthMap[(int)date('n', strtotime($p->calendar->from))] ?? null;
 
-            // Elenco corsi per tipologia in base al calendario
-            $courses = \App\Models\Course::where('name', $calendar->name)->where('date_from', '<=', $calendar->from)->where('date_to', '>=', $calendar->to)->pluck('id')->toArray();
+            if ((int)$p->calendar->status === 99) {
+                $statusHtml = "<span style=\"color:gray\">Annullata</span>";
+                $this->annullate++;
+                if ($idxMonth !== null) $chartData[2]['data'][$idxMonth]++;
+            } else {
+                $statusHtml = "<span style=\"color:#0c6197\">Presenza</span>";
+                $this->presenze++;
+                if ($idxMonth !== null) {
+                    $this->valori[$idxMonth]++;
+                    $chartData[0]['data'][$idxMonth]++;
+                }
 
-            //$courses = array(1);
-            foreach($courses as $c)
-            {
-                $course_ids[] = $c;    
+                $mot = ucfirst($p->motivation->name);
+                $this->recuperi[$mot] = ($this->recuperi[$mot] ?? 0) + 1;
             }
 
-            //$course_ids = array_push($course_ids, $courses);
-
+            $this->member_presences[] = [
+                'calendar_id' => $p->calendar->id,
+                'from' => $p->calendar->from,
+                'to'   => $p->calendar->to,
+                'status' => $statusHtml,
+                'motivation' => $p->motivation->name,
+            ];
         }
-        */
-        $course_ids = \App\Models\MemberCourse::where('member_id', $this->dataId)->pluck('course_id')->toArray();
-        
-        // Manuali (recuperi)
-        $calendar_recuperi = \App\Models\Calendar::where('manual', 1)->pluck('name')->toArray();
-        
-        // $this->presenceYears = \App\Models\Course::where('created_at', '>', '2025-08-01')->whereIn('id', $course_ids)->orderBy('year')->groupBy('year')->pluck('year')->toArray();
-        $this->presenceYears = \App\Models\Course::whereIn('id', $course_ids)->orderBy('year')->groupBy('year')->pluck('year')->toArray();
-        $this->presenceTitle = \App\Models\Course::whereIn('id', $course_ids)->orderBy('name')->groupBy('name')->pluck('name')->toArray();
 
-        foreach($calendar_recuperi as $cr)
-        {
-            $this->presenceTitle[] = $cr;
-        }
+        usort($this->member_presences, fn($a, $b) => strcmp($a['from'], $b['from']));
 
+        $this->emit('load-chart', $this->mesi, $this->valori, $chartData);
     }
 
     public function showDetailF($id)
@@ -1113,7 +1106,7 @@ class Member extends Component
             $to_complete = false;
             try {
                 $this->validate($std_rules);
-            } catch(\Illuminate\Validation\ValidationException $e) {
+            } catch (\Illuminate\Validation\ValidationException $e) {
                 $to_complete = true;
             }
 
@@ -1173,9 +1166,9 @@ class Member extends Component
                 $this->emit('saved-and-continue', $this->type);
                 $this->dispatchBrowserEvent('scroll-to-top');
                 if ($this->birth_nation_id != null)
-                    $this->isBirthItaly = \App\Models\Nation::findOrFail($this->birth_nation_id)->first()->is_italy;// $this->nation_id;//$this->checkIsItaly();
+                    $this->isBirthItaly = \App\Models\Nation::findOrFail($this->birth_nation_id)->first()->is_italy; // $this->nation_id;//$this->checkIsItaly();
                 if ($this->nation_id != null)
-                    $this->isItaly = \App\Models\Nation::findOrFail($this->nation_id)->first()->is_italy;// $this->nation_id;//$this->checkIsItaly();
+                    $this->isItaly = \App\Models\Nation::findOrFail($this->nation_id)->first()->is_italy; // $this->nation_id;//$this->checkIsItaly();
             }
             $this->emit('setEdit', false);
         } catch (\Exception $ex) {
@@ -1388,7 +1381,7 @@ class Member extends Component
             $to_complete = false;
             try {
                 $this->validate($std_rules);
-            } catch(\Illuminate\Validation\ValidationException $e) {
+            } catch (\Illuminate\Validation\ValidationException $e) {
                 $to_complete = true;
             }
 
@@ -1444,13 +1437,13 @@ class Member extends Component
                 //$this->resetFields();
                 //$this->update = false;
             } else {
-                
+
                 $this->emit('saved-and-continue', $this->type);
                 $this->dispatchBrowserEvent('scroll-to-top');
                 if ($this->birth_nation_id != null)
-                    $this->isBirthItaly = \App\Models\Nation::findOrFail($this->birth_nation_id)->first()->is_italy;// $this->nation_id;//$this->checkIsItaly();
+                    $this->isBirthItaly = \App\Models\Nation::findOrFail($this->birth_nation_id)->first()->is_italy; // $this->nation_id;//$this->checkIsItaly();
                 if ($this->nation_id != null)
-                    $this->isItaly = \App\Models\Nation::findOrFail($this->nation_id)->first()->is_italy;// $this->nation_id;//$this->checkIsItaly();
+                    $this->isItaly = \App\Models\Nation::findOrFail($this->nation_id)->first()->is_italy; // $this->nation_id;//$this->checkIsItaly();
             }
             $this->emit('setEdit', false);
         } catch (\Exception $ex) {
@@ -1770,83 +1763,76 @@ class Member extends Component
                 $course_name = $c->name;
             }
 
-            $days = array('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday');
+            $days = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
 
             //foreach($this->course_months as $m)
             //{
 
-                $from = date("Y-m-d", strtotime($c->date_from));
-                $to = date("Y-m-d", strtotime($c->date_to));
-
-                $endDate = strtotime($to);
-
-                foreach($this->course_when as $d)
-                {
-
-                    foreach($d["day"] as $dd)
-                    {
-
-                        $day = '';
-                        switch ($dd) {
-                            case 'lun':
-                                $day = $days[0];
-                                break;
-                            case 'mar':
-                                $day = $days[1];
-                                break;
-                            case 'mer':
-                                $day = $days[2];
-                                break;
-                            case 'gio':
-                                $day = $days[3];
-                                break;
-                            case 'ven':
-                                $day = $days[4];
-                                break;
-                            case 'sab':
-                                $day = $days[5];
-                                break;
-                            case 'dom':
-                                $day = $days[6];
-                                break;
-                            default:
-                                $day = '';
-                                break;
-                        }
-                        
-                        if ($day != '')
-                        {
-                            for($i = strtotime($day, strtotime($from)); $i <= $endDate; $i = strtotime('+1 week', $i))
-                            {
-
-                                // Controllo che non esiste un corso così
-                                $exist = \App\Models\Calendar::where('from', date('Y-m-d ' . $d["from"] . ":00", $i))->where('to', date('Y-m-d ' . $d["to"] . ":00", $i))->where('name', $course_name)->first();
-
-                                if (!$exist && !in_array(date('Y-m-d', $i), $this->festivita))
-                                {
-
-                                    // Creo il calendario del corso
-                                    $calendar = new \App\Models\Calendar();
-                                    $calendar->course_id = $this->course_course_id;
-                                    $calendar->court_id = null;
-                                    $calendar->name = $course_name;
-                                    $calendar->course_type_id = null;
-                                    $calendar->course_duration_id = null;
-                                    $calendar->course_frequency_id = null;
-                                    $calendar->course_level_id = null;
-                                    $calendar->instructor_id = null;
-                                    $calendar->from = date('Y-m-d ' . $d["from"] . ":00", $i);
-                                    $calendar->to = date('Y-m-d ' . $d["to"] . ":00", $i);
-                                    $calendar->note = '';
-                                    $calendar->status = 0;
-                                    $calendar->save();
+            $from = date("Y-m-d", strtotime($c->date_from));
+            $to = date("Y-m-d", strtotime($c->date_to));
 
-                                }
-                                
+            $endDate = strtotime($to);
+
+            foreach ($this->course_when as $d) {
+
+                foreach ($d["day"] as $dd) {
+
+                    $day = '';
+                    switch ($dd) {
+                        case 'lun':
+                            $day = $days[0];
+                            break;
+                        case 'mar':
+                            $day = $days[1];
+                            break;
+                        case 'mer':
+                            $day = $days[2];
+                            break;
+                        case 'gio':
+                            $day = $days[3];
+                            break;
+                        case 'ven':
+                            $day = $days[4];
+                            break;
+                        case 'sab':
+                            $day = $days[5];
+                            break;
+                        case 'dom':
+                            $day = $days[6];
+                            break;
+                        default:
+                            $day = '';
+                            break;
+                    }
+
+                    if ($day != '') {
+                        for ($i = strtotime($day, strtotime($from)); $i <= $endDate; $i = strtotime('+1 week', $i)) {
+
+                            // Controllo che non esiste un corso così
+                            $exist = \App\Models\Calendar::where('from', date('Y-m-d ' . $d["from"] . ":00", $i))->where('to', date('Y-m-d ' . $d["to"] . ":00", $i))->where('name', $course_name)->first();
+
+                            if (!$exist && !in_array(date('Y-m-d', $i), $this->festivita)) {
+
+                                // Creo il calendario del corso
+                                $calendar = new \App\Models\Calendar();
+                                $calendar->course_id = $this->course_course_id;
+                                $calendar->court_id = null;
+                                $calendar->name = $course_name;
+                                $calendar->course_type_id = null;
+                                $calendar->course_duration_id = null;
+                                $calendar->course_frequency_id = null;
+                                $calendar->course_level_id = null;
+                                $calendar->instructor_id = null;
+                                $calendar->from = date('Y-m-d ' . $d["from"] . ":00", $i);
+                                $calendar->to = date('Y-m-d ' . $d["to"] . ":00", $i);
+                                $calendar->note = '';
+                                $calendar->status = 0;
+                                $calendar->save();
                             }
                         }
                     }
                 }
+            }
             //}
 
             session()->flash('success, Corso creato');
@@ -1912,7 +1898,7 @@ class Member extends Component
                 }
                 $this->courseDataId = $memberCourse->id;
 
-                
+
                 $this->updateCourse = true;
                 $this->addCourse = false;
                 $this->emit('setEditCorso', true);
@@ -1957,7 +1943,7 @@ class Member extends Component
                 $course_name = $c->name;
             }
 
-            $days = array('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday');
+            $days = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
 
             //foreach($this->course_months as $m)
             //{
@@ -1967,11 +1953,9 @@ class Member extends Component
 
             $endDate = strtotime($to);
 
-            foreach($this->course_when as $d)
-            {
+            foreach ($this->course_when as $d) {
 
-                foreach($d["day"] as $dd)
-                {
+                foreach ($d["day"] as $dd) {
 
                     $day = '';
                     switch ($dd) {
@@ -2000,17 +1984,14 @@ class Member extends Component
                             $day = '';
                             break;
                     }
-                    
-                    if ($day != '')
-                    {
-                        for($i = strtotime($day, strtotime($from)); $i <= $endDate; $i = strtotime('+1 week', $i))
-                        {
+
+                    if ($day != '') {
+                        for ($i = strtotime($day, strtotime($from)); $i <= $endDate; $i = strtotime('+1 week', $i)) {
 
                             // Controllo che non esiste un corso così
                             $exist = \App\Models\Calendar::where('from', date('Y-m-d ' . $d["from"] . ":00", $i))->where('to', date('Y-m-d ' . $d["to"] . ":00", $i))->where('name', $course_name)->first();
 
-                            if (!$exist && !in_array(date('Y-m-d', $i), $this->festivita))
-                            {
+                            if (!$exist && !in_array(date('Y-m-d', $i), $this->festivita)) {
 
                                 // Creo il calendario del corso
                                 $calendar = new \App\Models\Calendar();
@@ -2027,9 +2008,7 @@ class Member extends Component
                                 $calendar->note = '';
                                 $calendar->status = 0;
                                 $calendar->save();
-
                             }
-                            
                         }
                     }
                 }
@@ -2327,7 +2306,9 @@ class Member extends Component
             $this->course_months[] = array("m" => $m, "status" => "");
         }
 
-        $rank = function (int $mm) { return ($mm - 9 + 12) % 12; };
+        $rank = function (int $mm) {
+            return ($mm - 9 + 12) % 12;
+        };
         usort($this->course_months, function ($a, $b) use ($rank) {
             return $rank((int)$a['m']) <=> $rank((int)$b['m']);
         });
@@ -2348,7 +2329,8 @@ class Member extends Component
 
                 $this->course_date_from = $start->format('Y-m-d');
                 $this->course_date_to   = $end->format('Y-m-d');
-            } catch (\Throwable $e) {}
+            } catch (\Throwable $e) {
+            }
         }
     }
 
@@ -2370,9 +2352,9 @@ class Member extends Component
 
                         if ($row->causal_id == $c->causal_id && !str_contains(strtolower($row->note), 'iscrizione')) {
                             $tot = sizeof(json_decode($row->when));
-                            foreach (json_decode($row->when) as $m) {
-                                $price -= $row->amount / $tot;
-                            }
+                            // foreach (json_decode($row->when) as $m) {
+                            $price -= $row->amount / $tot;
+                            // }
                         }
                     }
                 }
@@ -2634,7 +2616,8 @@ class Member extends Component
         return $ret;
     }
 
-    public function archiveMultiple($ids) {
+    public function archiveMultiple($ids)
+    {
         $success = true;
         foreach ($ids as $id) {
             $success = $this->archive($id, true);

+ 13 - 7
app/Http/Livewire/PaymentMethod.php

@@ -6,9 +6,10 @@ use Livewire\Component;
 
 class PaymentMethod extends Component
 {
-    public $records, $name, $enabled, $money, $type, $corrispettivo_fiscale, $dataId, $bank_id, $update = false, $add = false;
+    public $records, $name, $enabled, $money, $type, $corrispettivo_fiscale, $dataId, $origin_id, $destination_id, $update = false, $add = false;
 
-    public $banks = array();
+    public $origins = [];
+    public $destinations = [];
 
     protected $rules = [
         'name' => 'required'
@@ -47,7 +48,8 @@ class PaymentMethod extends Component
         if(\Auth::user()->level != env('LEVEL_ADMIN', 0))
             return redirect()->to('/dashboard');
 
-        $this->banks = \App\Models\Bank::select('id', 'name')->get();
+        $this->origins = \App\Models\Bank::select('id', 'name')->where('enabled', true)->whereIn('visibility', ['OUT', 'ALL'])->get();
+        $this->destinations = \App\Models\Bank::select('id', 'name')->where('enabled', true)->whereIn('visibility', ['IN', 'ALL'])->get();
     }
 
     public function render()
@@ -55,7 +57,8 @@ class PaymentMethod extends Component
         $this->records = \App\Models\PaymentMethod::all();
         foreach($this->records as $r)
         {
-            $r->bank = $r->bank ? $r->bank->name : '';
+            $r->origin = $r->origin ? $r->origin->name : '';
+            $r->destination = $r->destination ? $r->destination->name : '';
         }
         /*if ($this->sortAsc)
             $this->records = $this->records->sortBy($this->sortField);
@@ -77,7 +80,8 @@ class PaymentMethod extends Component
         try {
             \App\Models\PaymentMethod::create([
                 'name' => $this->name,
-                'bank_id' => $this->bank_id,
+                'origin_id' => $this->origin_id != "" ? $this->origin_id : null,
+                'destination_id' => $this->destination_id != "" ? $this->destination_id : null,
                 'money' => $this->money,
                 'type' => $this->type,
                 'corrispettivo_fiscale' => $this->corrispettivo_fiscale,
@@ -102,7 +106,8 @@ class PaymentMethod extends Component
                 $this->corrispettivo_fiscale = $payment_method->corrispettivo_fiscale;
                 $this->money = $payment_method->money;
                 $this->type = $payment_method->type;
-                $this->bank_id = $payment_method->bank_id;
+                $this->origin_id = $payment_method->origin_id;
+                $this->destination_id = $payment_method->destination_id;
                 $this->dataId = $payment_method->id;
                 $this->update = true;
                 $this->add = false;
@@ -118,7 +123,8 @@ class PaymentMethod extends Component
         try {
             \App\Models\PaymentMethod::whereId($this->dataId)->update([
                 'name' => $this->name,
-                'bank_id' => $this->bank_id,
+                'origin_id' => $this->origin_id != "" ? $this->origin_id : null,
+                'destination_id' => $this->destination_id != "" ? $this->destination_id : null,
                 'money' => $this->money,
                 'type' => $this->type,
                 'corrispettivo_fiscale' => $this->corrispettivo_fiscale,

+ 122 - 6
app/Http/Livewire/Presence.php

@@ -29,6 +29,19 @@ class Presence extends Component
     public $motivations = [];
     public $motivations_add = [];
 
+    public $insertUser = 'exist';
+    public $course_limit;
+    public $motivation_course_id = null;
+    public $motivation_course_name = 0;
+    public $motivation_course_level = 0;
+    public $motivation_course_type = 0;
+    public $motivation_course_frequency = 0;
+
+    public $course_names = [];
+    public $course_levels = [];
+    public $course_types = [];
+    public $course_frequencies = [];
+
     public $members = [];
 
     public $newMembers = [];
@@ -62,6 +75,86 @@ class Presence extends Component
         $this->save_court_id = 0;
         $this->save_instructor_id = 0;
         $this->save_notes = '';
+
+        $this->insertUser = 'exist';
+        $this->course_limit = now()->endOfDay();
+
+        $this->course_names = \App\Models\Course::whereDate('date_from', '<=', $this->course_limit)->whereDate('date_to', '>=', $this->course_limit)->where('active', true)->where('enabled', true)->orderBy('name')->groupBy('name')->pluck('name');
+        $this->course_levels = [];
+        $this->course_types = [];
+        $this->course_frequencies = [];
+    }
+
+    function updatedMotivationCourseName() {
+        if ($this->motivation_course_name > 0 && $this->motivation_course_name != '') {
+            $this->motivation_course_id = null;
+            $this->motivation_course_level = 0;
+            $this->motivation_course_type = 0;
+            $this->motivation_course_frequency = 0;
+
+            $levels_ids = [];
+            $levels = \App\Models\Course::whereDate('date_from', '<=', $this->course_limit)->whereDate('date_to', '>=', $this->course_limit)->where('active', true)->where('enabled', true)->where('name', $this->motivation_course_name)->get();
+            foreach ($levels as $l) {
+                $levels_ids[] = $l->course_level_id;
+            }
+
+            $this->course_levels = \App\Models\CourseLevel::where('enabled', true)->whereIn('id', $levels_ids)->orderBy('name')->get();
+            $this->course_types = [];
+            $this->course_frequencies = [];
+        } else {
+            $this->course_levels = [];
+            $this->course_types = [];
+            $this->course_frequencies = [];
+        }
+    }
+
+    function updatedMotivationCourseLevel() {
+        if ($this->motivation_course_name > 0 && $this->motivation_course_name != '' && $this->motivation_course_level > 0 && $this->motivation_course_level != '') {
+            $this->motivation_course_id = null;
+            $this->motivation_course_type = 0;
+            $this->motivation_course_frequency = 0;
+
+            $type_ids = [];
+            $types = \App\Models\Course::whereDate('date_from', '<=', $this->course_limit)->whereDate('date_to', '>=', $this->course_limit)->where('active', true)->where('enabled', true)->where('name', $this->motivation_course_name)->where('course_level_id', $this->motivation_course_level)->get();
+            foreach ($types as $t) {
+                $type_ids[] = $t->course_type_id;
+            }
+
+            $this->course_types = \App\Models\CourseType::where('enabled', true)->whereIn('id', $type_ids)->orderBy('name')->get();
+            $this->course_frequencies = [];
+        } else {
+            $this->course_types = [];
+            $this->course_frequencies = [];
+        }
+    }
+
+    function updatedMotivationCourseType() {
+        if ($this->motivation_course_name > 0 && $this->motivation_course_name != '' && $this->motivation_course_level > 0 && $this->motivation_course_level != '' && $this->motivation_course_type > 0 && $this->motivation_course_type != '') {
+            $this->motivation_course_id = null;
+            $this->motivation_course_frequency = 0;
+
+            $frequency_ids = [];
+            $frequencies = \App\Models\Course::whereDate('date_from', '<=', $this->course_limit)->whereDate('date_to', '>=', $this->course_limit)->where('active', true)->where('enabled', true)->where('name', $this->motivation_course_name)->where('course_level_id', $this->motivation_course_level)->where('course_type_id', $this->motivation_course_type)->get();
+            foreach ($frequencies as $f) {
+                $frequency_ids[] = $f->course_frequency_id;
+            }
+
+            $this->course_frequencies = \App\Models\CourseFrequency::where('enabled', true)->whereIn('id', $frequency_ids)->orderBy('name')->get();
+        } else {
+            $this->course_frequencies = [];
+        }
+    }
+
+    function updatedMotivationCourseFrequency() {
+        if ($this->motivation_course_name > 0 && $this->motivation_course_name != '' && $this->motivation_course_level > 0 && $this->motivation_course_level != '' && $this->motivation_course_type > 0 && $this->motivation_course_type != '' && $this->motivation_course_frequency > 0 && $this->motivation_course_frequency != '') {
+            $this->motivation_course_id = null;
+
+            $course = \App\Models\Course::whereDate('date_from', '<=', $this->course_limit)->whereDate('date_to', '>=', $this->course_limit)->where('active', true)->where('enabled', true)->where('name', $this->motivation_course_name)->where('course_level_id', $this->motivation_course_level)->where('course_type_id', $this->motivation_course_type)->where('course_frequency_id', $this->motivation_course_frequency)->first();
+
+            $this->motivation_course_id = $course->id;
+        } else {
+            $this->motivation_course_id = null;
+        }
     }
 
     public function updatedNewMemberMotivationId()
@@ -302,8 +395,9 @@ class Presence extends Component
         // Mappa degli ultimi motivation_id per ogni member_id dell'utente e calendario correnti
         $userId     = \Auth::user()->id;
         $calendarId = $this->calendar->id;
-        $lastEditData = \App\Models\Presence::query()
-            ->select('member_id', 'motivation_id')
+
+        $motivation_query = \App\Models\Presence::query()
+            ->select('member_id', 'motivation_id', 'motivation_course_id')
             ->where('calendar_id', $calendarId)
             ->where('user_id', $userId)
             ->where('status', '<>', 99)
@@ -316,9 +410,10 @@ class Presence extends Component
                     ->groupBy('member_id');
             })
             ->get()
-            ->keyBy('member_id')   // -> [member_id => (obj con motivation_id)]
-            ->map(fn($row) => $row->motivation_id)
-            ->toArray();
+            ->keyBy('member_id');
+
+        $motivationMap = $motivation_query->map(fn($row) => $row->motivation_id)->toArray();
+        $motivationCourseMap = $motivation_query->map(fn($row) => $row->motivation_course_id)->toArray();
 
         // Elimino tutti i dati correnti che devono essere sostituiti
         \App\Models\Presence::query()
@@ -334,7 +429,8 @@ class Presence extends Component
             $p->calendar_id = $calendarId;
 
             // Se per quel membro esisteva un motivation_id, lo riuso, altrimenti lo lascio null
-            $p->motivation_id = $lastEditData[$id] ?? null;
+            $p->motivation_id = $motivationMap[$id] ?? null;
+            $p->motivation_course_id = $motivationCourseMap[$id] ?? null;
             $p->user_id = $userId;
             $p->status = 0;
 
@@ -429,6 +525,7 @@ class Presence extends Component
                 $p->member_id = $member->id;
                 $p->calendar_id = $this->calendar->id;
                 $p->motivation_id = $this->newMemberMotivationId;
+                $p->motivation_course_id = $this->motivation_course_id;
                 $p->user_id = \Auth::user()->id;
                 $p->status = 0;
                 $p->court_id = null;
@@ -461,6 +558,7 @@ class Presence extends Component
                     $p->member_id = $m;
                     $p->calendar_id = $this->calendar->id;
                     $p->motivation_id = $this->newMemberMotivationId;
+                    $p->motivation_course_id = $this->motivation_course_id;
                     $p->user_id = \Auth::user()->id;
                     $p->status = 0;
                     $p->court_id = null;
@@ -484,6 +582,24 @@ class Presence extends Component
             $this->emit('reload');
             $this->emit('saved');
         }
+
+        $this->resetCreationFields();
+    }
+
+    public function resetCreationFields() {
+        $this->insertUser = 'new';
+        $this->motivation_course_id = null;
+        $this->motivation_course_name = null;
+        $this->motivation_course_level = null;
+        $this->motivation_course_type = null;
+        $this->motivation_course_frequency = null;
+        $this->newMemberMotivationId = null;
+        $this->newMemberFirstName = null;
+        $this->newMemberLastName = null;
+        $this->newMemberEmail = null;
+        $this->newMemberFiscalCode = null;
+
+        $this->emit('resetCreationForm');
     }
 
     public function createInstructor()

+ 179 - 225
app/Http/Livewire/PresenceReport.php

@@ -3,35 +3,18 @@
 namespace App\Http\Livewire;
 
 use Livewire\Component;
+use Illuminate\Support\Carbon;
 
 class PresenceReport extends Component
 {
-
-    public $calendar;
-
-    public $records;
-
+    public $records = [];
     public $date;
 
-    public $member_ids = [];
-
-
     public $courses = [];
     public $courts = [];
     public $instructors = [];
     public $motivations = [];
 
-    public $court_filter;
-    public $instructor_filter;
-    public $motivation_filter;
-
-
-    public $members = [];
-
-    public $newMembers = [];
-
-    public $ids = [];
-
     public $course_name;
     public $from;
     public $to;
@@ -44,14 +27,14 @@ class PresenceReport extends Component
 
     public function mount()
     {
-        $this->courts = \App\Models\Court::select('*')->where('enabled', true)->get();
-        $this->instructors = \App\Models\User::select('*')->where('level', 2)->where('enabled', true)->orderBy('name', 'asc')->get();
-        $this->motivations = \App\Models\Motivation::select('*')->where('enabled', true)->where('type', 'del')->get();
+        $this->courts = \App\Models\Court::where('enabled', true)->orderBy('name')->get();
+        $this->instructors = \App\Models\User::where('level', 2)->where('enabled', true)->orderBy('name')->get();
+        $this->motivations = \App\Models\Motivation::where('enabled', true)->where('type', 'del')->orderBy('name')->get();
 
         $this->from = "00:00:00";
         $this->to = "23:59:59";
-
         $this->date = date("Y-m-d");
+
         setlocale(LC_ALL, 'it_IT');
     }
 
@@ -60,254 +43,225 @@ class PresenceReport extends Component
         setlocale(LC_ALL, 'it_IT');
 
         $this->records = [];
-        $this->courses = [];
-
-        $from = $this->date . " " . $this->from;
-        $to = $this->date . " " . $this->to;
-
-        $calendars = \App\Models\Calendar::where('from', '>=', $from)->where('from', '<=', $to)->orderBy('from')->get();
 
-        if (!is_null($this->court_id) && $this->court_id > 0)
-            $this->court_name = \App\Models\Court::findOrFail($this->court_id)->name;
-        else
-            $this->court_name = '';
+        $fromDt = Carbon::parse($this->date . ' ' . ($this->from ?: '00:00:00'));
+        $toDt = Carbon::parse($this->date . ' ' . ($this->to ?: '23:59:59'));
 
-        if (!is_null($this->instructor_id) && $this->instructor_id > 0)
-            $this->instructor_name = \App\Models\User::findOrFail($this->instructor_id)->name;
-        else
-            $this->instructor_name = '';
+        $this->court_name = '';
+        if (!empty($this->court_id)) {
+            $court = $this->courts->firstWhere('id', (int)$this->court_id);
+            $this->court_name = $court?->name ?? '';
+        }
 
-        foreach ($calendars as $calendar) {
+        $this->instructor_name = '';
+        if (!empty($this->instructor_id)) {
+            $instr = $this->instructors->firstWhere('id', (int)$this->instructor_id);
+            $this->instructor_name = $instr?->name ?? '';
+        }
 
-            $presences = \App\Models\Presence::where('calendar_id', $calendar->id)->where('status', '<>', 99);
-            $presences_annullate = \App\Models\Presence::where('calendar_id', $calendar->id)->where('status', 99);
-            
-            // filtra per campo court_id
-            if (!is_null($this->court_id) && $this->court_id > 0) {
-                $presences->where('court_id', $this->court_id);
-                $presences_annullate->where('court_id', $this->court_id);
-            }
+        $calendars = \App\Models\Calendar::with(['course.level'])
+            ->whereBetween('from', [$fromDt->toDateTimeString(), $toDt->toDateTimeString()])
+            ->orderBy('from')
+            ->get();
 
-            // filtra per campo istructor_id/user_id
-            if (!is_null($this->instructor_id) && $this->instructor_id > 0) {
-                $presences->where(function ($query) {
-                    $query->where('instructor_id', $this->instructor_id)
-                        ->orWhere('user_id', $this->instructor_id);
-                });
-                $presences_annullate->where(function ($query) {
-                    $query->where('instructor_id', $this->instructor_id)
-                        ->orWhere('user_id', $this->instructor_id);
-                });
-            }
+        if ($calendars->isEmpty()) {
+            $this->courses = \App\Models\Calendar::orderBy('name')->groupBy('name')->pluck('name')->toArray();
+            return view('livewire.presence_report');
+        }
 
-            // filtra per campo search (nome/cognome)
-            if (!is_null($this->search) && $this->search != "") {
-                $search_value = $this->search;
-                $presences->whereHas('member', function ($q) use ($search_value) {
-                    $q->where(function ($qq) use ($search_value) {
-                        $qq->whereRaw("CONCAT(TRIM(first_name), ' ', TRIM(last_name)) LIKE ?", ["%{$search_value}%"])
-                        ->orWhereRaw("CONCAT(TRIM(last_name), ' ', TRIM(first_name)) LIKE ?", ["%{$search_value}%"]);
-                    });
+        $calendarIds = $calendars->pluck('id')->all();
+
+        $presencesAll = \App\Models\Presence::with([
+            'member:id,first_name,last_name',
+            'court:id,name',
+            'user:id,name',
+            'instructor:id,name',
+            'motivation:id,name',
+            'motivationCourse:id,name',
+        ])
+            ->whereIn('calendar_id', $calendarIds)
+            ->when(!empty($this->court_id), fn($q) => $q->where('court_id', (int)$this->court_id))
+            ->when(!empty($this->instructor_id), function ($q) {
+                $iid = (int)$this->instructor_id;
+                $q->where(function ($qq) use ($iid) {
+                    $qq->where('instructor_id', $iid)->orWhere('user_id', $iid);
                 });
-                $presences_annullate->whereHas('member', function ($q) use ($search_value) {
-                    $q->where(function ($qq) use ($search_value) {
-                        $qq->whereRaw("CONCAT(TRIM(first_name), ' ', TRIM(last_name)) LIKE ?", ["%{$search_value}%"])
-                        ->orWhereRaw("CONCAT(TRIM(last_name), ' ', TRIM(first_name)) LIKE ?", ["%{$search_value}%"]);
+            })
+            ->when(!empty($this->search), function ($q) {
+                $s = trim($this->search);
+                $q->whereHas('member', function ($mq) use ($s) {
+                    $mq->where(function ($qq) use ($s) {
+                        $qq->whereRaw("CONCAT(TRIM(first_name), ' ', TRIM(last_name)) LIKE ?", ["%{$s}%"])
+                            ->orWhereRaw("CONCAT(TRIM(last_name), ' ', TRIM(first_name)) LIKE ?", ["%{$s}%"]);
                     });
                 });
-            }
+            })
+            ->get();
 
-            $presences = $presences->pluck('member_id')->toArray();
-            $presences_annullate = $presences_annullate->pluck('member_id')->toArray();
+        $presenceByCalMember = [];
+        $presencesByCalendar = [];
 
-            $days = ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'];
-            $dow = date('w', strtotime($calendar->from));
-            $d = $days[$dow];
+        foreach ($presencesAll as $p) {
+            $presenceByCalMember[$p->calendar_id . '|' . $p->member_id] = $p;
+            $presencesByCalendar[$p->calendar_id][] = $p;
+        }
 
-            $h = date('H:i', strtotime($calendar->from));
+        $days = ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'];
 
-            // Elenco corsi per tipologia in base al calendario
-            $courses = \App\Models\Course::where('name', $calendar->name)->where('date_from', '<=', $calendar->from)->where('date_to', '>=', $calendar->to);
-            if (!is_null($this->course_name) && $this->course_name != "") {
-                $courses = $courses->where('name', $this->course_name);
+        foreach ($calendars as $calendar) {
+            $h = Carbon::parse($calendar->from)->format('H:i');
+            $dow = (int) Carbon::parse($calendar->from)->format('w'); // 0..6
+            $d = $days[$dow];
+            $month = (int) Carbon::parse($calendar->from)->format('n');
+
+            $courseIds = \App\Models\Course::query()
+                ->where('name', $calendar->name)
+                ->where('date_from', '<=', $calendar->from)
+                ->where('date_to', '>=', $calendar->to)
+                ->when(!empty($this->course_name), fn($q) => $q->where('name', $this->course_name))
+                ->pluck('id')
+                ->toArray();
+
+            if (empty($courseIds)) {
+                continue;
             }
-            $courses = $courses->pluck('id')->toArray();
-
-            $mids = [];
 
-            $months = date("n", strtotime($calendar->from));
-
-            // Elenco utenti iscritti al corso "padre"
-            $members = \App\Models\MemberCourse::where('when', 'like', "%" . $d . "%")
+            $membersQuery = \App\Models\MemberCourse::with(['member', 'course.level'])
+                ->whereIn('course_id', $courseIds)
+                ->where('when', 'like', "%{$d}%")
                 ->where('when', 'like', '%"from":"' . $h . '"%')
-                ->whereDate('date_from', '<=', $calendar->from)                                 
-                ->whereDate('date_to', '>=', $calendar->from)      
-                ->whereNot('months', 'like', '%"m":' . $months . ',"status":2%')
-                ->whereIn('course_id', $courses);
-                
-            if (!is_null($this->search) && $this->search != "") {
-                $search_value = $this->search;
-                $members->whereHas('member', function ($q) use ($search_value) {
-                    $q->where(function ($qq) use ($search_value) {
-                        $qq->whereRaw("CONCAT(TRIM(first_name), ' ', TRIM(last_name)) LIKE ?", ["%{$search_value}%"])
-                        ->orWhereRaw("CONCAT(TRIM(last_name), ' ', TRIM(first_name)) LIKE ?", ["%{$search_value}%"]);
+                ->whereDate('date_from', '<=', $calendar->from)
+                ->whereDate('date_to', '>=', $calendar->from)
+                ->whereNot('months', 'like', '%"m":' . $month . ',"status":2%');
+
+            if (!empty($this->search)) {
+                $s = trim($this->search);
+                $membersQuery->whereHas('member', function ($mq) use ($s) {
+                    $mq->where(function ($qq) use ($s) {
+                        $qq->whereRaw("CONCAT(TRIM(first_name), ' ', TRIM(last_name)) LIKE ?", ["%{$s}%"])
+                            ->orWhereRaw("CONCAT(TRIM(last_name), ' ', TRIM(first_name)) LIKE ?", ["%{$s}%"]);
                     });
                 });
             }
 
-            $members = $members->get();
+            $members = $membersQuery->get();
 
-            //$members = \App\Models\MemberCourse::where('when', 'like', "%" . $d . "%")->where('when', 'like', '%"from":"' . $h . '"%')->whereIn('member_id', $presences)->whereIn('course_id', $courses)->get();
-            foreach ($members as $member) {
+            $expectedMemberIds = [];
 
-                $court = '';
-                $instructor = '';
-                $motivation = '';
+            foreach ($members as $mc) {
+                $mid = $mc->member->id;
+                $expectedMemberIds[] = $mid;
 
-                $presence = \App\Models\Presence::where('member_id', $member->member->id)->where('calendar_id', $calendar->id)->first();
-                if ($presence) {
-                    $court = $presence->court ? $presence->court->name : "";
-                    $instructor = [
-                        $presence->user ? $presence->user->name : "",
-                        $presence->instuctor && $presence->instructor !== $presence->user ? $presence->instuctor->name : "",
-                    ];
-                    $instructor = implode(", ", array_filter($instructor));
-                    $motivation = $presence->motivation ? $presence->motivation->name : "";
-                }
+                $p = $presenceByCalMember[$calendar->id . '|' . $mid] ?? null;
 
-                $status = '';
-                if (in_array($member->member->id, $presences)) {
-                    $status = "<span class='fw-bold' style='color:#0c6197'>Presente</span>";
-                } else {
-                    if (in_array($member->member->id, $presences_annullate)) {
-                        $status = "<span class='fw-bold' style='color:gray'>Annullata</span>";
-                    } else {
-                        if (date("Ymd") > date("Ymd", strtotime($calendar->from))) {
-                            $status = "<span class='fw-bold' style='color:red'>Assente</span>";
-                        }
-                    }
+                [$court, $instructor, $motivation] = $this->presenceMeta($p);
+
+                $status = $this->presenceStatusHtml($p, $calendar);
+
+                $course_level = '';
+                if ($mc->course && $mc->course->level) {
+                    $course_level = trim($mc->course->level->name);
                 }
 
-                if ($calendar->status == 99) {
-                    $status = "<span class='fw-bold' style='color:gray'>Annullata</span>";
+                $this->records[$calendar->name][$h][] = [
+                    'course_level' => $course_level,
+                    'last_name' => $mc->member->last_name,
+                    'first_name' => $mc->member->first_name,
+                    'court' => $court,
+                    'instructor' => $instructor,
+                    'status' => $status,
+                    'motivation' => $motivation,
+                ];
+            }
+
+            $extras = $presencesByCalendar[$calendar->id] ?? [];
+
+            foreach ($extras as $p) {
+                if (in_array($p->member_id, $expectedMemberIds, true)) {
+                    continue;
                 }
 
-                $show = true;
-                if ($this->court_name != '')
-                    $show = $this->court_name == $court;
-                if ($show && $this->instructor_name != '')
-                    $show = $this->instructor_name == $instructor;
-
-                if ($show)
-                {
-                    $course_level = "";
-                    if ($member->course && $member->course->level) {
-                        $course_level = trim($member->course->level->name);
+                if (!empty($this->course_name)) {
+                    $motCourseName = $p->motivationCourse?->name;
+                    if (!$motCourseName || $motCourseName !== $this->course_name) {
+                        continue;
                     }
-                    $this->records[$calendar->name][$h][] = array(
-                        "course_level" => $course_level,
-                        "last_name" => $member->member->last_name,
-                        "first_name" => $member->member->first_name,
-                        "court" => $court,
-                        "instructor" => $instructor,
-                        "status" => $status,
-                        'motivation' => $motivation
-                    );
-
-                    $mids[] = $member->member->id;
                 }
-            }
 
-            $presences_recuperi = \App\Models\Presence::join('calendars', 'presences.calendar_id', '=', 'calendars.id')
-                ->join('courses', 'calendars.course_id', '=', 'courses.id')
-                ->where('calendar_id', $calendar->id)
-                ->whereNotIn('member_id', $mids);
-            if (!is_null($this->course_name) && $this->course_name != "") {
-                $presences_recuperi = $presences_recuperi->where('courses.name', $this->course_name);
-            }
-            if (!is_null($this->court_id) && $this->court_id > 0) {
-                $presences_recuperi->where('court_id', $this->court_id);
-            }
-            if (!is_null($this->instructor_id) && $this->instructor_id > 0) {
-                $presences_recuperi->where(function ($query) {
-                    $query->where('instructor_id', $this->instructor_id)
-                        ->orWhere('user_id', $this->instructor_id);
-                });
-            }
-            if (!is_null($this->search) && $this->search != "") {
-                $search_value = $this->search;
-                $presences_recuperi->whereHas('member', function ($q) use ($search_value) {
-                    $q->where(function ($qq) use ($search_value) {
-                        $qq->whereRaw("CONCAT(TRIM(first_name), ' ', TRIM(last_name)) LIKE ?", ["%{$search_value}%"])
-                        ->orWhereRaw("CONCAT(TRIM(last_name), ' ', TRIM(first_name)) LIKE ?", ["%{$search_value}%"]);
-                    });
-                });
-            }
-            $presences_recuperi = $presences_recuperi->get();
-            // dd($courses, $members, $presences_recuperi, $calendar->from, $calendar->to);
-            foreach ($presences_recuperi as $p) {
-                $court = $p->court ? $p->court->name : "";
-                $instructor = [
-                    $p->user ? $p->user->name : "",
-                    $p->instuctor && $p->instructor !== $p->user ? $p->instuctor->name : "",
-                ];
-                $instructor = implode(", ", array_filter($instructor));
-                $motivation = $p->motivation ? $p->motivation->name : "";
-                // $status = "<span class='fw-bold' style='color:gray'>Recupero</span>";
-                $status = "<span class='fw-bold' style='color:#0c6197'>Presente</span>";
-                
-                $course_level = "";
+                [$court, $instructor, $motivation] = $this->presenceMeta($p);
+                $status = $this->presenceStatusHtml($p, $calendar);
+
+                $course_level = '';
                 if ($calendar->course && $calendar->course->level) {
                     $course_level = trim($calendar->course->level->name);
                 }
-                $this->records[$calendar->name][$h][] = array(
-                    "course_level" => $course_level,
-                    "last_name" => $p->member->last_name,
-                    "first_name" => $p->member->first_name,
-                    "court" => $court,
-                    "instructor" => $instructor,
-                    "status" => $status,
-                    'motivation' => $motivation
-                );
+
+                $this->records[$calendar->name][$h][] = [
+                    'course_level' => $course_level,
+                    'last_name' => $p->member?->last_name ?? '',
+                    'first_name' => $p->member?->first_name ?? '',
+                    'court' => $court,
+                    'instructor' => $instructor,
+                    'status' => $status,
+                    'motivation' => $motivation,
+                ];
             }
 
-            /*
-            $calendar_recuperi = \App\Models\Calendar::where('manual', 1)->where('id', $calendar->id)->pluck('id')->toArray();
-            $presences_recuperi = \App\Models\Presence::whereIn('calendar_id', $calendar_recuperi)->where('member_id', $this->dataId)->get();
-            foreach($presences_recuperi as $p)
-            {
-                $this->member_presences[] = array('calendar_id' => $p->calendar->id, 'from' => $p->calendar->from, 'to' => $p->calendar->to, 'status' => '<span style="color:#7136f6">Recupero</span>');//\App\Models\Presence::where('member_id', $this->dataId)->get();
-                $this->recuperi += 1;
-            } 
-                */
-
-            //array_push($this->courses, $calendar->course_id);
-
-            // sort records per cognome-nome
-            if (isset($this->records[$calendar->name]) && isset($this->records[$calendar->name][$h])) {
-                usort($this->records[$calendar->name][$h], function($a, $b) {
+            if (isset($this->records[$calendar->name][$h])) {
+                usort($this->records[$calendar->name][$h], function ($a, $b) {
                     $course_level_compare = strcmp($a['course_level'], $b['course_level']);
+                    if ($course_level_compare !== 0) return $course_level_compare;
+
                     $last_name_compare = strcmp($a['last_name'], $b['last_name']);
-                    $first_name_compare = strcmp($a['first_name'], $b['first_name']);
-                    
-                    return $course_level_compare != 0 ? $course_level_compare : ($last_name_compare != 0 ? $last_name_compare : $first_name_compare);
+                    if ($last_name_compare !== 0) return $last_name_compare;
+
+                    return strcmp($a['first_name'], $b['first_name']);
                 });
             }
         }
 
         $this->courses = \App\Models\Calendar::orderBy('name')->groupBy('name')->pluck('name')->toArray();
 
-        /*$this->courses = array_unique($this->courses);
-        $this->courses = array_map(function ($course_id) {
-            try {
-                return \App\Models\Course::findOrFail($course_id);
-            } catch (\Throwable $e) {
-                return null;
+        return view('livewire.presence_report');
+    }
+
+    protected function presenceStatusHtml($presence, $calendar): string
+    {
+        if ($calendar->status == 99) {
+            return "<span class='fw-bold' style='color:gray'>Annullata</span>";
+        }
+
+        if ($presence) {
+            if ((int)$presence->status === 99) {
+                return "<span class='fw-bold' style='color:gray'>Annullata</span>";
             }
-        }, $this->courses);
-        $this->courses = array_filter($this->courses);*/
+            return "<span class='fw-bold' style='color:#0c6197'>Presente</span>";
+        }
 
-        return view('livewire.presence_report');
+        if (Carbon::now()->format('Ymd') > Carbon::parse($calendar->from)->format('Ymd')) {
+            return "<span class='fw-bold' style='color:red'>Assente</span>";
+        }
+
+        return '';
+    }
+
+    protected function presenceMeta($presence): array
+    {
+        if (!$presence) return ['', '', ''];
+
+        $court = $presence->court?->name ?? '';
+
+        $instructorParts = [
+            $presence->user?->name ?? '',
+            ($presence->instructor && $presence->user && $presence->instructor->id !== $presence->user->id)
+                ? $presence->instructor->name
+                : ($presence->instructor?->name ?? ''),
+        ];
+        $instructor = implode(', ', array_values(array_filter(array_unique($instructorParts))));
+
+        $motivation = $presence->motivation?->name ?? '';
+
+        return [$court, $instructor, $motivation];
     }
 
     public function prev()

+ 58 - 0
app/Http/Livewire/Record.php

@@ -21,6 +21,8 @@ class Record extends Component
     public $in;
     public $out;
     public $payments = [];
+    public $origins = [];
+    public $destinations = [];
     public $fromDate;
     public $toDate;
     public $appliedFromDate;
@@ -31,6 +33,8 @@ class Record extends Component
     public $selectedPeriod = 'OGGI';
     public $filterCausals = null;
     public $filterPaymentMethods = null;
+    public $filterOrigins = null;
+    public $filterDestinations = null;
     public $filterMember = null;
     public $isFiltering = false;
     public array $recordDatas = [];
@@ -91,6 +95,8 @@ class Record extends Component
             })->orderBy('last_name')->orderBy('first_name')->get();
 
         $this->payments = \App\Models\PaymentMethod::select('id', 'name', 'type')->where('enabled', true)->where('money', false)->get();
+        $this->origins = \App\Models\Bank::select('id', 'name')->where('enabled', true)->whereIn('visibility', ['OUT', 'ALL'])->get();
+        $this->destinations = \App\Models\Bank::select('id', 'name')->where('enabled', true)->whereIn('visibility', ['IN', 'ALL'])->get();
 
         $this->selectedMonth = date('Y-m');
         $this->selectedDay = date('Y-m-d');
@@ -168,6 +174,16 @@ class Record extends Component
             Log::info('generateExportDataAndTotals: Payment method filters applied', ['payment_method_count' => count($this->filterPaymentMethods)]);
         }
 
+        if ($this->filterOrigins != null && sizeof($this->filterOrigins) > 0) {
+            $datas->whereIn('origin_id', $this->filterOrigins);
+            Log::info('generateExportDataAndTotals: Origin filters applied', ['origins_count' => count($this->filterOrigins)]);
+        }
+
+        if ($this->filterDestinations != null && sizeof($this->filterDestinations) > 0) {
+            $datas->whereIn('destination_id', $this->filterDestinations);
+            Log::info('generateExportDataAndTotals: Destination filters applied', ['destinations_count' => count($this->filterDestinations)]);
+        }
+
         if ($this->filterMember != null && $this->filterMember > 0) {
             $datas->where('member_id', $this->filterMember);
             Log::info('generateExportDataAndTotals: Member filter applied', ['member_id' => $this->filterMember]);
@@ -395,6 +411,12 @@ class Record extends Component
         if ($this->filterPaymentMethods != null && sizeof($this->filterPaymentMethods) > 0) {
             $datas->whereIn('payment_method_id', $this->filterPaymentMethods);
         }
+        if ($this->filterOrigins != null && sizeof($this->filterOrigins) > 0) {
+            $datas->whereIn('origin_id', $this->filterOrigins);
+        }
+        if ($this->filterDestinations != null && sizeof($this->filterDestinations) > 0) {
+            $datas->whereIn('destination_id', $this->filterDestinations);
+        }
         if ($this->filterMember != null && $this->filterMember > 0) {
             $datas->where('member_id', $this->filterMember);
         }
@@ -437,6 +459,8 @@ class Record extends Component
         $this->showDayPicker = false;
         $this->filterCausals = [];
         $this->filterPaymentMethods = [];
+        $this->filterOrigins = [];
+        $this->filterDestinations = [];
         $this->filterMember = null;
 
         $today = date("Y-m-d");
@@ -638,6 +662,12 @@ class Record extends Component
         if ($this->filterPaymentMethods != null && sizeof($this->filterPaymentMethods) > 0) {
             $datas->whereIn('payment_method_id', $this->filterPaymentMethods);
         }
+        if ($this->filterOrigins != null && sizeof($this->filterOrigins) > 0) {
+            $datas->whereIn('origin_id', $this->filterOrigins);
+        }
+        if ($this->filterDestinations != null && sizeof($this->filterDestinations) > 0) {
+            $datas->whereIn('destination_id', $this->filterDestinations);
+        }
         if ($this->filterMember != null && $this->filterMember > 0) {
             $datas->where('member_id', $this->filterMember);
         }
@@ -1079,6 +1109,12 @@ class Record extends Component
         if ($this->filterPaymentMethods != null && sizeof($this->filterPaymentMethods) > 0) {
             $query->whereIn('payment_method_id', $this->filterPaymentMethods);
         }
+        if ($this->filterOrigins != null && sizeof($this->filterOrigins) > 0) {
+            $query->whereIn('origin_id', $this->filterOrigins);
+        }
+        if ($this->filterDestinations != null && sizeof($this->filterDestinations) > 0) {
+            $query->whereIn('destination_id', $this->filterDestinations);
+        }
 
         if ($this->filterMember != null && $this->filterMember > 0) {
             $query->where('member_id', $this->filterMember);
@@ -1113,6 +1149,26 @@ class Record extends Component
         return implode(', ', $payment_methods);
     }
 
+    private function getOriginsNames($originIds)
+    {
+        if (!is_array($originIds)) {
+            return null;
+        }
+
+        $origins = \App\Models\Bank::whereIn('id', $originIds)->pluck('name')->toArray();
+        return implode(', ', $origins);
+    }
+
+    private function getDestinationsNames($destinationIds)
+    {
+        if (!is_array($destinationIds)) {
+            return null;
+        }
+
+        $destinations = \App\Models\Bank::whereIn('id', $destinationIds)->pluck('name')->toArray();
+        return implode(', ', $destinations);
+    }
+
     public function updatedExportFromDate()
     {
         $this->updateEmailSubject();
@@ -1164,6 +1220,8 @@ class Record extends Component
                 'member' => $this->filterMember ? $this->getMemberName($this->filterMember) : null,
                 'causals' => $this->filterCausals ? $this->getCausalsNames($this->filterCausals) : null,
                 'payment_methods' => $this->filterPaymentMethods ? $this->getPaymentMethodsNames($this->filterPaymentMethods) : null,
+                'origins' => $this->filterOrigins ? $this->getOriginsNames($this->filterOrigins) : null,
+                'destinations' => $this->filterDestinations ? $this->getDestinationsNames($this->filterDestinations) : null,
             ];
 
             $paymentsArray = $this->payments->map(function ($payment) {

+ 32 - 2
app/Http/Livewire/RecordIN.php

@@ -68,6 +68,7 @@ class RecordIN extends Component
     $commercial, $update = false, $add = false;
 
     public $corrispettivo = [];
+    public $corrispettivo_destination = [];
 
     public $currentReceip;
 
@@ -162,9 +163,25 @@ class RecordIN extends Component
 
     public function updatedPaymentMethodId() {
         //$this->emit('refresh');
+
+        if ($this->payment_method_id) {
+            $payment_method = \App\Models\PaymentMethod::findOrFail($this->payment_method_id);
+            $this->destination_id = $payment_method->destination_id ?? null;
+        }
+
         $this->canSave = $this->checkCanSave();
     }
 
+    public function updatedCorrispettivoFiscale() {
+        if ($this->corrispettivo_fiscale) {
+            foreach ($this->payments as $payment) {
+                if ($payment->corrispettivo_fiscale) {
+                    $this->corrispettivo_destination[$payment->id] = $payment->destination_id;
+                }
+            }
+        }
+    }
+
     public function updatedAmount() {
         // $this->emit('refresh');
         $this->canSave = $this->checkCanSave();
@@ -268,6 +285,7 @@ class RecordIN extends Component
         $this->rows = array();
         $this->rows[] = array('causal_id' => isset($_GET["causalId"]) ? $_GET["causalId"] : null, 'when' => array(array('month' => date("n"), 'year' => date("Y"), 'period' => '')),  'amount' => null, 'vat_id' => null, 'note' => '', 'commercial' => 0);
         $this->corrispettivo = [];
+        $this->corrispettivo_destination = [];
         $this->emit('load-data-table');
     }
 
@@ -311,6 +329,16 @@ class RecordIN extends Component
         return $ret;
     }
 
+    public function getBankName($bank_id)
+    {
+        $ret = '';
+        if ($bank_id > 0)
+        {
+            $ret = \App\Models\Bank::findOrFail($bank_id)->name;
+        }
+        return $ret;
+    }
+
     function buildTree($records, $parentId = 0) {
         $this->causals = array();
 
@@ -523,6 +551,7 @@ class RecordIN extends Component
             if ($p->corrispettivo_fiscale)
             {
                 $price = isset($this->corrispettivo[$p->id]) ? $this->currencyToDouble($this->corrispettivo[$p->id]) : 0;
+                $destination_id = isset($this->corrispettivo_destination[$p->id]) ? $this->corrispettivo_destination[$p->id] : null;
 
                 if ($price > 0)
                 {
@@ -531,6 +560,7 @@ class RecordIN extends Component
                         'member_id' => $this->member_id,
                         'supplier_id' => null,
                         'payment_method_id' => $p->id,
+                        'destination_id' => $destination_id,
                         'commercial' => $this->commercial,
                         'corrispettivo_fiscale' => $this->corrispettivo_fiscale,
                         'date' => $this->date,
@@ -886,7 +916,7 @@ class RecordIN extends Component
                 \App\Models\Record::find($this->dataId)->delete();
                 session()->flash('success',"Movimento eliminato");
             }catch(\Exception $e){
-                session()->flash('error','Errore (' . $ex->getMessage() . ')');
+                session()->flash('error','Errore (' . $e->getMessage() . ')');
             }
         }
         $this->isDuplicate = false;
@@ -955,7 +985,7 @@ class RecordIN extends Component
                 \App\Models\Record::find($id)->delete();
             }
         }catch(\Exception $e){
-            session()->flash('error','Errore (' . $ex->getMessage() . ')');
+            session()->flash('error','Errore (' . $e->getMessage() . ')');
         }
         $this->multipleAction = '';
     }

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

@@ -211,7 +211,10 @@ class RecordINOUT extends Component
                     ->where(function ($query) {
                         $query->where('financial_movement', false)->orWhere('financial_movement', null);
                     })
-                    ->whereNotIn('member_id', $exclude_from_records)
+                    ->where(function ($query) use ($exclude_from_records) {
+                        $query->whereNotIn('member_id', $exclude_from_records)
+                            ->orWhere('member_id', null);
+                    })
                     ->whereRaw('records_rows.when REGEXP ?', [$pairs]);
                 $incomeRecords = $incomeQuery->get();
 
@@ -250,7 +253,10 @@ class RecordINOUT extends Component
                     ->where(function ($query) {
                         $query->where('financial_movement', false)->orWhere('financial_movement', null);
                     })
-                    ->whereNotIn('member_id', $exclude_from_records)
+                    ->where(function ($query) use ($exclude_from_records) {
+                        $query->whereNotIn('member_id', $exclude_from_records)
+                            ->orWhere('member_id', null);
+                    })
                     ->whereRaw('records_rows.when REGEXP ?', [$pairs]);
                 $expenseRecords = $expenseQuery->get();
 
@@ -505,7 +511,10 @@ class RecordINOUT extends Component
                 ->where(function ($query) {
                     $query->where('financial_movement', false)->orWhere('financial_movement', null);
                 })
-                ->whereNotIn('member_id', $exclude_from_records)
+                ->where(function ($query) use ($exclude_from_records) {
+                    $query->whereNotIn('member_id', $exclude_from_records)
+                        ->orWhere('member_id', null);
+                })
                 ->where('records_rows.when', 'like', '%"' . $filter . '"%')->get();
             //$records = $records->orderBy('date', 'DESC')->get();
 
@@ -535,7 +544,10 @@ class RecordINOUT extends Component
                 ->where(function ($query) {
                     $query->where('financial_movement', false)->orWhere('financial_movement', null);
                 })
-                ->whereNotIn('member_id', $exclude_from_records)
+                ->where(function ($query) use ($exclude_from_records) {
+                    $query->whereNotIn('member_id', $exclude_from_records)
+                        ->orWhere('member_id', null);
+                })
                 ->where('records_rows.when', 'like', '%"' . $filter . '"%')->get();
             //$records = $records->orderBy('date', 'DESC')->get();
 

+ 7 - 0
app/Http/Livewire/RecordOUT.php

@@ -163,6 +163,13 @@ class RecordOUT extends Component
         $this->banks = \App\Models\Bank::select('id', 'name')->where('enabled', true)->whereIn('visibility', array('ALL', 'OUT'))->orderBy('name')->get();
     }
 
+    public function updatedPaymentMethodId() {
+        if ($this->payment_method_id) {
+            $payment_method = \App\Models\PaymentMethod::findOrFail($this->payment_method_id);
+            $this->origin_id = $payment_method->origin_id ?? null;
+        }
+    }
+
     public function getCausal($causal)
     {
         $ret = '';

+ 8 - 0
app/Jobs/ExportPrimaNota.php

@@ -879,6 +879,14 @@ class ExportPrimaNota implements ShouldQueue
             $descriptions[] = "Metodi di pagamento: " . (is_array($this->filters['payment_methods']) ? implode(', ', $this->filters['payment_methods']) : $this->filters['payment_methods']);
         }
 
+        if (!empty($this->filters['origins'])) {
+            $descriptions[] = "Origini: " . (is_array($this->filters['origins']) ? implode(', ', $this->filters['origins']) : $this->filters['origins']);
+        }
+
+        if (!empty($this->filters['destinations'])) {
+            $descriptions[] = "Destinazioni: " . (is_array($this->filters['destinations']) ? implode(', ', $this->filters['destinations']) : $this->filters['destinations']);
+        }
+
         return empty($descriptions) ? 'Nessun filtro applicato' : implode(' | ', $descriptions);
     }
 

+ 1 - 1
app/Models/Bank.php

@@ -19,7 +19,7 @@ class Bank extends Model
 
     public function canDelete()
     {
-        return \App\Models\PaymentMethod::where('bank_id', $this->id)->count() == 0;
+        return \App\Models\PaymentMethod::where('origin_id', $this->id)->orWhere('destination_id', $this->id)->count() == 0;
     }
 
     public function getVisibility()

+ 11 - 0
app/Models/Course.php

@@ -129,4 +129,15 @@ class Course extends Model
         return \App\Models\MemberCourse::where('course_id', $this->id)->count();
     }
 
+    public function getDetailsName() {
+        $courseName = $this->name ?? 'Corso Sconosciuto';
+        $levelName = is_object($this->level) ? $this->level->name : '';
+        $frequencyName = is_object($this->frequency) ? $this->frequency->name : '';
+
+        $displayNameParts = [$courseName];
+        if ($levelName) $displayNameParts[] = $levelName;
+        if ($frequencyName) $displayNameParts[] = $frequencyName;
+
+        return implode(' - ', $displayNameParts);
+    }
 }

+ 8 - 3
app/Models/PaymentMethod.php

@@ -15,12 +15,17 @@ class PaymentMethod extends Model
         'type',
         'corrispettivo_fiscale',
         'enabled',
-        'bank_id'
+        'origin_id',
+        'destination_id'
     ];
 
-    public function bank()
+    public function origin()
     {
-        return $this->belongsTo(\App\Models\Bank::class);
+        return $this->belongsTo(\App\Models\Bank::class, 'origin_id', 'id');
     }
 
+    public function destination()
+    {
+        return $this->belongsTo(\App\Models\Bank::class, 'destination_id', 'id');
+    }
 }

+ 6 - 0
app/Models/Presence.php

@@ -15,6 +15,7 @@ class Presence extends Model
         'member_course_id',
         'user_id',
         'motivation_id',
+        'motivation_course_id',
         'court_id',
         'instructor_id',
         'notes',
@@ -35,6 +36,11 @@ class Presence extends Model
         return $this->belongsTo(\App\Models\Motivation::class);
     }
 
+    public function motivationCourse()
+    {
+        return $this->belongsTo(\App\Models\Course::class, 'motivation_course_id');
+    }
+
     public function user()
     {
         return $this->belongsTo(\App\Models\User::class, 'user_id');

+ 41 - 0
database/migrations/2025_12_10_094113_add_origin_destination_to_payment_methods_table.php

@@ -0,0 +1,41 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+
+return new class extends Migration
+{
+    public function up()
+    {
+        Schema::table('payment_methods', function (Blueprint $table) {
+            $table->dropForeign('payment_methods_bank_id_foreign');
+        });
+
+        DB::statement('ALTER TABLE `payment_methods` CHANGE `bank_id` `origin_id` BIGINT(20) UNSIGNED NULL');
+
+        Schema::table('payment_methods', function (Blueprint $table) {
+            $table->unsignedBigInteger('destination_id')->nullable()->after('origin_id');
+
+            $table->foreign('origin_id', 'payment_methods_origin_id_foreign')->references('id')->on('banks')->onUpdate('cascade')->onDelete('cascade');
+
+            $table->foreign('destination_id', 'payment_methods_destination_id_foreign')->references('id')->on('banks')->onUpdate('cascade')->onDelete('cascade');
+        });
+    }
+
+    public function down()
+    {
+        Schema::table('payment_methods', function (Blueprint $table) {
+            $table->dropForeign('payment_methods_destination_id_foreign');
+            $table->dropForeign('payment_methods_origin_id_foreign');
+            $table->dropColumn('destination_id');
+        });
+
+        DB::statement('ALTER TABLE `payment_methods`CHANGE `origin_id` `bank_id` BIGINT(20) UNSIGNED NULL');
+
+        Schema::table('payment_methods', function (Blueprint $table) {
+            $table->foreign('bank_id', 'payment_methods_bank_id_foreign')->references('id')->on('banks')->onUpdate('cascade')->onDelete('cascade');
+        });
+    }
+};

+ 35 - 0
database/migrations/2025_12_15_100649_add_motivation_course_id_to_presences_table.php

@@ -0,0 +1,35 @@
+<?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('presences', function (Blueprint $table) {
+            $table->unsignedBigInteger('motivation_course_id')->nullable()->after('motivation_id');
+
+            $table->foreign('motivation_course_id', 'presences_motivation_course_id_foreign')->references('id')->on('courses')->onUpdate('cascade')->onDelete('cascade');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('presences', function (Blueprint $table) {
+            $table->dropForeign('presences_motivation_course_id_foreign');
+            $table->dropColumn('motivation_course_id');
+        });
+    }
+};

+ 1 - 1
public/css/style.css

@@ -16723,7 +16723,7 @@ div.dt-container div.dt-length label {
   }
 
   #resume-table.records-table {
-    height: calc(100dvh - (86px + 195px)) !important;
+    height: calc(100dvh - (86px + 280px)) !important;
   }
 
   #card--dashboard:has(.showFilter.filter_shown) #resume-table.course_list-table {

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

@@ -208,6 +208,10 @@
                 print "Profilo utenti";
             if (Request::is('reports'))
                 print "Reports";
+            if (Request::is('presence_reports'))
+                print "Report presenze";
+            if (Request::is('absence_reports'))
+                print "Assenze";
             @endphp
             </h3>
 

+ 61 - 4
resources/views/livewire/absence_report.blade.php

@@ -1,6 +1,6 @@
 <div class="col card--ui" id="card--dashboard">
 
-    <a class="btn--ui lightGrey" href="/presence_reports"><i class="fa-solid fa-arrow-left"></i></a><br>
+    <a class="btn--ui lightGrey" href="/presence_reports"><i class="fa-solid fa-arrow-left"></i></a>
 
     <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">
@@ -8,10 +8,67 @@
             <h2 class="primary">Assenze</h2>
         </div>
     </header>
+    
+    <div class="row mb-2">
+        <div class="col">
+            <div class="alert alert-warning text-center" role="alert">Attenzione: se un utente viene aggiunto manualmente a un corso diverso da quello a cui è associato, l'utente continuerà a risultare assente nel corso a cui è regolarmente iscritto.</div>
+        </div>
+    </div>
+    
+    <div class="row mb-2">
+        <div class="col">
+            <div class="alert alert-info text-center" role="alert">I dati sono aggiornati al giorno precedente della data odierna.</div>
+        </div>
+    </div>
 
-    <br>
+    <div class="row mb-3">
+        <div class="col-8"></div>
+        <div class="col text-end">
+            <div class="input-group">
+                <input type="text" class="form-control" placeholder="Cerca utente" aria-label="Cerca utente" wire:model.defer="search">
+            </div>
+        </div>
+        <div class="col-auto text-end">
+            <button class="btn--ui" type="button" wire:click="resetSearch()">Reset</button>
+            &nbsp;
+            <button class="btn--ui" type="button" wire:click="applySearch()">Cerca</button>
+        </div>
+    </div>
 
-    <div class="row">
+    @foreach ($record_assenze as $record_data)
+        <div class="row mb-5">
+            <div class="col-12 mb-2">
+                <h3 class="primary">{{$record_data['course']['name']}}</h3>
+            </div>
+            <div class="col-12">
+                <table class="report-table">
+                    <thead>
+                        <tr>
+                            <td style="width: 20%">Cognome</td>
+                            <td style="width: 20%">Nome</td>
+                            <td style="width: 10%">N. assenze</td>
+                            <td>Date</td>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        @foreach($record_data['members'] as $member)
+                        <tr @if($loop->index % 2 == 1)style="background-color: rgba(12 97 151 / 0.05);"@endif>
+                            <td>{{$member['member']['last_name']}}</td>
+                            <td>{{$member['member']['first_name']}}</td>
+                            <td>{{$member["count"]}}</td>
+                            <td>
+                                @foreach ($member["dates"] as $calendar_date)
+                                    <a href="/presences?calendarId={{$calendar_date['calendar_id']}}" target="_blank">{{$calendar_date['date']}}</a>@if (!$loop->last) - @endif
+                                @endforeach
+                            </td>
+                        </tr>
+                        @endforeach
+                    </tbody>
+                </table>
+            </div>
+        </div>
+    @endforeach
+    {{-- <div class="row">
         <div class="col-12 mb-3">
             <h3 class="primary">Assenze {{$year}}/{{$year+1}}</h3>
         </div>
@@ -39,7 +96,7 @@
                 </tbody>
             </table>
         </div>
-    </div>
+    </div> --}}
 </div>
 
 @push('css')

+ 55 - 47
resources/views/livewire/member.blade.php

@@ -1133,86 +1133,94 @@
                                 @if($type == 'presenze')
 
                                     <div class="form--wrapper">
-                                        <div class="row ">
+                                        <div class="row">
                                             <div class="col-md-6">
                                                 <select class="form-control" wire:model="presenceYearFilter">
+                                                    <option value="">-- Stagione --</option>
                                                     @foreach($presenceYears as $y)
                                                         <option value="{{$y}}">{{$y}}</option>
                                                     @endforeach
                                                 </select>
                                             </div>
+
                                             <div class="col-md-6">
-                                                <select class="form-control"  wire:model="presenceTitleFilter">                                                    
-                                                    @foreach($presenceTitle as $t)
-                                                        <option value="{{$t}}">{{$t}}</option>
+                                                <select class="form-control" wire:model="presenceCourseFilter" @if(empty($presenceCourses)) disabled @endif>
+                                                    <option value="">-- Corso --</option>
+                                                    @foreach($presenceCourses as $c)
+                                                        <option value="{{$c->id}}">
+                                                            {{$c->getDetailsName()}}
+                                                        </option>
                                                     @endforeach
                                                 </select>
                                             </div>
                                         </div>
+
                                         <br>
+
                                         <div class="row align-items-center">
-                                            <div class="col-md-3">
+                                            <div class="col">
                                                 <div class="box-presenze">
-                                                    Presenze<br>
-                                                    {{$presenze}}
-                                                </div>                                                
+                                                    <span><b>Presenze</b>: {{ $presenze }}</span>
+                                                </div>
                                             </div>
-                                            <div class="col-md-3">
+                                            <div class="col">
                                                 <div class="box-assenze">
-                                                    Assenze<br>
-                                                    {{$assenze}}
+                                                    <span><b>Assenze</b>: {{ $assenze }}</span>
                                                 </div>
                                             </div>
-                                            <div class="col-md-3" style="border-right: 1px solid gray">
+                                            <div class="col"@if (!empty($recuperi)) style="border-right: 1px solid gray"@endif>
                                                 <div class="box-annullate">
-                                                    Annullate<br>
-                                                    {{$annullate}}
+                                                    <span><b>Annullate</b>: {{ $annullate }}</span>
                                                 </div>
                                             </div>
-                                            <div class="col-md-3">
-                                                <div class="row">
-                                                    {{-- <div class="col-12"><div class="box-recupero">Recupero {{$recuperi}}</div></div>
-                                                    <div class="col-12"><div class="box-recupero">Recupero {{$recuperi}}</div></div> --}}
-                                                    @foreach ($recuperi as $name => $count)
-                                                    <div class="col-12"><div class="box-presenze">{!!$name!!} {{$count}}</div></div>
-                                                    @endforeach
-                                                    {{-- <div class="col-12"><div class="box-presenze">Recupero {{$recuperi}}</div></div> --}}
+                                            @if (!empty($recuperi))
+                                                <div class="col">
+                                                    <div class="box-presenze text-start">
+                                                        @foreach ($recuperi as $name => $count)
+                                                            <span><b>{!! $name !!}</b>: {{ $count }}</span><br>
+                                                        @endforeach
+                                                    </div>
                                                 </div>
-                                            </div>
-                                        </div>                                        
-                                        <div class="row ">
+                                            @endif
+                                        </div>
+
+                                        <div class="row">
                                             <div class="col-md-12">
                                                 <div class="presenzechart-wrapper">
                                                     <canvas id="presenzeChart" style="padding:20px"></canvas>
-                                                    <button class="btn--ui download-png" onclick="downloadChart('presenzeChart')" data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-placement="bottom" data-bs-content="Scarica grafico"><i class="fas fa-download"></i></button>
+                                                    <button class="btn--ui download-png" onclick="downloadChart('presenzeChart')" data-bs-toggle="popover"
+                                                        data-bs-trigger="hover focus" data-bs-placement="bottom" data-bs-content="Scarica grafico">
+                                                        <i class="fas fa-download"></i>
+                                                    </button>
                                                 </div>
                                             </div>
                                         </div>
+
                                         @if (!empty($member_presences))
-                                        <div class="row " style="height: 300px; overflow:auto; ">
-                                            <div class="col-md-12">
-                                                <table class="table tablesaw tableHead tablesaw-stack tabella--presenze" id="tablesaw-350-2" style="min-width:700px">
-                                                    <thead>
-                                                        <tr>
-                                                            <th>Data</th>
-                                                            <th>Orario</th>
-                                                            <th>Stato</th>
-                                                            <th>Motivazione</th>
-                                                        </tr>                                                        
-                                                    </thead>
-                                                    <tbody>
-                                                        @foreach($member_presences as $mp)
+                                            <div class="row" style="height: 300px; overflow:auto;">
+                                                <div class="col-md-12">
+                                                    <table class="table tablesaw tableHead tablesaw-stack tabella--presenze" style="min-width:700px">
+                                                        <thead>
                                                             <tr>
-                                                                <td>{{date("d/m/Y", strtotime($mp["from"]))}}</td>
-                                                                <td>{{date("H:i", strtotime($mp["from"]))}} - {{date("H:i", strtotime($mp["to"]))}}</td>
-                                                                <td>{!!$mp["status"]!!}</td>
-                                                                <td>{!!$mp["motivation"]!!}</td>
+                                                                <th style="width: 20%">Data</th>
+                                                                <th style="width: 20%">Orario</th>
+                                                                <th style="width: 15%">Stato</th>
+                                                                <th style="width: 45%">Motivazione</th>
                                                             </tr>
-                                                        @endforeach
-                                                    </tbody>
-                                                </table>
+                                                        </thead>
+                                                        <tbody>
+                                                            @foreach($member_presences as $mp)
+                                                                <tr>
+                                                                    <td>{{ date("d/m/Y", strtotime($mp["from"])) }}</td>
+                                                                    <td>{{ date("H:i", strtotime($mp["from"])) }} - {{ date("H:i", strtotime($mp["to"])) }}</td>
+                                                                    <td>{!! $mp["status"] !!}</td>
+                                                                    <td>{!! $mp["motivation"] !!}</td>
+                                                                </tr>
+                                                            @endforeach
+                                                        </tbody>
+                                                    </table>
+                                                </div>
                                             </div>
-                                        </div>
                                         @endif
                                     </div>
 

+ 29 - 14
resources/views/livewire/payment_method.blade.php

@@ -28,7 +28,8 @@
             <table class="table tablesaw tableHead tablesaw-stack" id="tablesaw-350" width="100%">
                 <thead>
                     <tr>
-                        <th scope="col">Banca</th>
+                        <th scope="col">Origine</th>
+                        <th scope="col">Destinazione</th>
                         <th scope="col">Nome</th>
                         <th scope="col">Tipo</th>
                         <th scope="col">Abilitato</th>
@@ -38,7 +39,8 @@
                 <tbody id="checkall-target">
                     @foreach($records as $record)
                         <tr>
-                            <td>{{$record->bank ? $record->bank : ''}}</td>
+                            <td>{{$record->origin ? $record->origin : ''}}</td>
+                            <td>{{$record->destination ? $record->destination : ''}}</td>
                             <td>{{$record->name}}</td>
                             <td>
                                 @php
@@ -118,18 +120,6 @@
                                     @enderror
                                 </div>
                             </div>
-
-                            <div class="col">
-                                <label for="bank_id" class="form-label">Banca</label>
-                                <select name="bank_id" class="form-select" aria-label="Seleziona una banca" wire:model="bank_id">
-                                    <option value="">--Seleziona--
-                                    @foreach($banks as $bank)
-                                        <option value="{{$bank->id}}">{{$bank->name}}
-                                    @endforeach
-                                </select>
-                            </div>
-                        </div>
-                        <div class="row mb-3">
                             <div class="col-md-6">
                                 <label for="type" class="form-label">Tipologia</label>
                                 <select name="type" class="form-select" aria-label="Seleziona una tipologia" wire:model="type">
@@ -139,6 +129,28 @@
                                 </select>
                             </div>
                         </div>
+                        <div class="row mb-3">
+
+                            <div class="col">
+                                <label for="origin_id" class="form-label">Origine</label>
+                                <select name="origin_id" class="form-select" aria-label="Seleziona un'origine" wire:model="origin_id">
+                                    <option value="">--Seleziona--
+                                    @foreach($origins as $origin)
+                                        <option value="{{$origin->id}}">{{$origin->name}}
+                                    @endforeach
+                                </select>
+                            </div>
+
+                            <div class="col">
+                                <label for="destination_id" class="form-label">Destinazione</label>
+                                <select name="destination_id" class="form-select" aria-label="Seleziona una destinazione" wire:model="destination_id">
+                                    <option value="">--Seleziona--
+                                    @foreach($destinations as $destination)
+                                        <option value="{{$destination->id}}">{{$destination->name}}
+                                    @endforeach
+                                </select>
+                            </div>
+                        </div>
 
                         <div class="form--item mb-3">
                             <div class="form--item">
@@ -210,6 +222,9 @@
                 thead: {
                 'th': {'background-color': 'blue'}
                 },
+                order: [
+                    [2, 'asc']
+                ],
                 layout: {
                     topStart : null,
                     topEnd : null,

+ 97 - 1
resources/views/livewire/presence.blade.php

@@ -237,9 +237,10 @@
                 </div>
                 <div class="modal-body">
                     <h3 class="text-primary"><input type="radio" name="chkType" value="1" checked onchange="change(1)"> Utente già registrato</h3>
+                    @if ($insertUser == 'exist')
                     <div class="existUser">
                         <div class="row mt-2 ">
-                            <div class="col-md-6">
+                            <div class="col-md-6" wire:ignore>
                                 <label for="member_id" class="form-label">Aggiungere una o più persone</label>
                                 <select name="member_id" class="form-select memberClass" aria-label="Seleziona una persona" multiple>
                                     <option value="">--Seleziona--
@@ -257,13 +258,57 @@
                                     @endforeach
                                 </select>
                             </div>
+                            <div class="col-md-6">
+                                <label for="motivation_course_name" class="form-label">Corso</label>
+                                <select class="form-select form-select-lg me-1 @error('motivation_course_name') is-invalid @enderror" id="motivation_course_name" wire:model="motivation_course_name">
+                                    <option value="">
+                                    @foreach($course_names as $m)
+                                        <option value="{{$m}}">{{$m}}</option>
+                                    @endforeach
+                                </select>
+                            </div>
+                            @if ($motivation_course_name)
+                                <div class="col-md-6">
+                                    <label for="motivation_course_level" class="form-label">Livello</label>
+                                    <select class="form-select form-select-lg me-1 @error('motivation_course_level') is-invalid @enderror" id="motivation_course_level" wire:model="motivation_course_level">
+                                        <option value="">
+                                            @foreach($course_levels as $m)
+                                            <option value="{{$m["id"]}}">{{$m["name"]}}</option>
+                                            @endforeach
+                                        </select>
+                                </div>
+                                @if ($motivation_course_level)
+                                    <div class="col-md-6">
+                                        <label for="motivation_course_type" class="form-label">Tipologia</label>
+                                        <select class="form-select form-select-lg me-1 @error('motivation_course_type') is-invalid @enderror" id="motivation_course_type" wire:model="motivation_course_type">
+                                            <option value="">
+                                            @foreach($course_types as $m)
+                                                <option value="{{$m["id"]}}">{{$m["name"]}}</option>
+                                            @endforeach
+                                        </select>
+                                    </div>
+                                    @if ($motivation_course_type)
+                                        <div class="col-md-6">
+                                            <label for="motivation_course_frequency" class="form-label">Frequenza</label>
+                                            <select class="form-select form-select-lg me-1 @error('motivation_course_frequency') is-invalid @enderror" id="motivation_course_frequency" wire:model="motivation_course_frequency">
+                                                <option value="">
+                                                @foreach($course_frequencies as $m)
+                                                    <option value="{{$m["id"]}}">{{$m["name"]}}</option>
+                                                @endforeach
+                                            </select>
+                                        </div>
+                                    @endif
+                                @endif
+                            @endif
                         </div>
                     </div>
+                    @endif
                     <br>
                     <hr>
                     <br>
                     <h3 class="text-primary"><input type="radio" name="chkType" value="2" onchange="change(2)"> Inserimento nuovo utente</h3>
                     <br>
+                    @if ($insertUser == 'new')
                     <div class="newUser">
                         @if($newMemberFiscalCodeExist)
                         <span style="color:red">Attenzione, utente esistente</span>
@@ -302,8 +347,51 @@
                                     @endforeach
                                 </select>
                             </div>
+                            <div class="col-md-6">
+                                <label for="motivation_course_name" class="form-label">Corso</label>
+                                <select class="form-select form-select-lg me-1 @error('motivation_course_name') is-invalid @enderror" id="motivation_course_name" wire:model="motivation_course_name">
+                                    <option value="">
+                                    @foreach($course_names as $m)
+                                        <option value="{{$m}}">{{$m}}</option>
+                                    @endforeach
+                                </select>
+                            </div>
+                            @if ($motivation_course_name)
+                                <div class="col-md-6">
+                                    <label for="motivation_course_level" class="form-label">Livello</label>
+                                    <select class="form-select form-select-lg me-1 @error('motivation_course_level') is-invalid @enderror" id="motivation_course_level" wire:model="motivation_course_level">
+                                        <option value="">
+                                            @foreach($course_levels as $m)
+                                            <option value="{{$m["id"]}}">{{$m["name"]}}</option>
+                                            @endforeach
+                                        </select>
+                                </div>
+                                @if ($motivation_course_level)
+                                    <div class="col-md-6">
+                                        <label for="motivation_course_type" class="form-label">Tipologia</label>
+                                        <select class="form-select form-select-lg me-1 @error('motivation_course_type') is-invalid @enderror" id="motivation_course_type" wire:model="motivation_course_type">
+                                            <option value="">
+                                            @foreach($course_types as $m)
+                                                <option value="{{$m["id"]}}">{{$m["name"]}}</option>
+                                            @endforeach
+                                        </select>
+                                    </div>
+                                    @if ($motivation_course_type)
+                                        <div class="col-md-6">
+                                            <label for="motivation_course_frequency" class="form-label">Frequenza</label>
+                                            <select class="form-select form-select-lg me-1 @error('motivation_course_frequency') is-invalid @enderror" id="motivation_course_frequency" wire:model="motivation_course_frequency">
+                                                <option value="">
+                                                @foreach($course_frequencies as $m)
+                                                    <option value="{{$m["id"]}}">{{$m["name"]}}</option>
+                                                @endforeach
+                                            </select>
+                                        </div>
+                                    @endif
+                                @endif
+                            @endif
                         </div>
                     </div>
+                    @endif
                 </div>
                 <div class="modal-footer">
                     <button class="btn--ui lightGrey" onclick="annulla()">annulla</a>
@@ -698,14 +786,22 @@
 
         function change(val) {
             if (val == 1) {
+                @this.insertUser = 'exist';
                 $(".existUser").css("display", "block");
                 $(".newUser").css("display", "none");
             } else if (val == 2) {
+                @this.insertUser = 'new';
                 $(".newUser").css("display", "block");
                 $(".existUser").css("display", "none");
             } 
             type = val;
         }
+
+        Livewire.on('resetCreationForm', () => {
+            @this.insertUser = 'exist';
+            $(".existUser").css("display", "block");
+            $(".newUser").css("display", "none");
+        });
         
 </script>
 @endpush

+ 13 - 8
resources/views/livewire/presence_report.blade.php

@@ -24,13 +24,18 @@
                 <i class="fa-solid fa-chevron-left"></i>
             </a>
             @php
-                $date_title = \Illuminate\Support\Carbon::parse($date)->locale('it-IT')->translatedFormat("j F Y");
+                $date = \Illuminate\Support\Carbon::parse($date);
+                $date_back = $date->format('Y-m-d');
+                $date_title = $date->locale('it-IT')->translatedFormat("j F Y");
             @endphp
             <h4 class="text-uppercase m-0">{{$date_title}}</h4>
             <a style="cursor:pointer;" wire:click="next()">
                 <i class="fa-solid fa-chevron-right"></i>
             </a>
         </div>
+        <div class="col-auto">
+            <a class="btn--ui btn-primary" style="cursor:pointer;" href='/calendar?last_date={{$date_back}}'>Vai al calendario</a>
+        </div>
         <div class="col-auto">
             <a class="btn--ui btn-primary" style="cursor:pointer;" href='/absence_reports'>Alert assenze</a>
         </div>
@@ -109,13 +114,13 @@
                     <table class="report-table">
                         <thead>
                             <tr>
-                                <td>Livello</td>
-                                <td>Cognome</td>
-                                <td>Nome</td>
-                                <td>Campo</td>
-                                <td>Istruttore</td>
-                                <td>Stato</td>
-                                <td>Motivazione</td>
+                                <td style="width: 15%">Livello</td>
+                                <td style="width: 15%">Cognome</td>
+                                <td style="width: 15%">Nome</td>
+                                <td style="width: 10%">Campo</td>
+                                <td style="width: 15%">Istruttore</td>
+                                <td style="width: 10%">Stato</td>
+                                <td style="width: 20%">Motivazione</td>
                             </tr>
                         </thead>
                         <tbody>

+ 120 - 14
resources/views/livewire/records.blade.php

@@ -27,15 +27,7 @@
                     @endforeach
                 </select>
             </div>
-            <div class="col-md-2">
-                Metodo di pagamento
-                <select name="search_payment_method[]" class="form-select filterPaymentMethods me-2" multiple="multiple" wire:model="filterPaymentMethods">
-                    @foreach($payments as $payment)
-                        <option value="{{$payment["id"]}}">{!!$payment["name"]!!}
-                    @endforeach
-                </select>
-            </div>
-            <div class="col-md-2">
+            <div class="col-md-3">
                 Periodo
                 <div class="col-12 mb-3">
                     <select wire:model="selectedPeriod" class="form-select" @if($isFiltering) disabled @endif style="height: 43px!important;">
@@ -267,7 +259,33 @@
                 @endif
                 @endif
             </div>
-            <div class="col-md-2">
+        </div>
+        <div class="row g-3">
+            <div class="col-md-3">
+                Metodo di pagamento
+                <select name="search_payment_method[]" class="form-select filterPaymentMethods me-2" multiple="multiple" wire:model="filterPaymentMethods">
+                    @foreach($payments as $payment)
+                        <option value="{{$payment["id"]}}">{!!$payment["name"]!!}
+                    @endforeach
+                </select>
+            </div>
+            <div class="col-md-3">
+                Origine
+                <select name="search_origin[]" class="form-select filterOrigins me-2" multiple="multiple" wire:model="filterOrigins">
+                    @foreach($origins as $origin)
+                        <option value="{{$origin["id"]}}">{!!$origin["name"]!!}
+                    @endforeach
+                </select>
+            </div>
+            <div class="col-md-3">
+                Destinazione
+                <select name="search_destination[]" class="form-select filterDestinations me-2" multiple="multiple" wire:model="filterDestinations">
+                    @foreach($destinations as $destination)
+                        <option value="{{$destination["id"]}}">{!!$destination["name"]!!}
+                    @endforeach
+                </select>
+            </div>
+            <div class="col">
                 <div class="prima--nota_buttons ms-auto" style="float:right; margin-top:25px;">
                     <button class="btn--ui primary" wire:click="applyFilters" style="margin-right:5px;" @if($isFiltering) disabled @endif>
                         @if($isFiltering)
@@ -347,7 +365,7 @@
                     <th scope="col">Stato</th>
                     <th scope="col" class="text-end">Entrata</th>
                     <th scope="col" class="text-end">Uscita</th>
-                    <th scope="col">Origine</th>
+                    <th scope="col" style="padding-left: 20px;">Origine</th>
                     <th scope="col">Destinazione</th>
                     <th scope="col">Metodo di pagamento</th>
                 </tr>
@@ -371,12 +389,12 @@
                         <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: 20%;white-space: pre-line;">{{$record->causal_name}}</td>
-                            <td style="background-color: {{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{$record->type == 'IN' ? ($record->member->first_name . " " . $record->member->last_name) : @$record->supplier->name}}</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'}}">{{$record->type == 'OUT' ? $record->origin : ''}}</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>
                         </tr>
@@ -1349,6 +1367,16 @@
                     $(this).select2('close');
                 }
             });
+            $('.filterOrigins').each(function() {
+                if ($(this).hasClass('select2-hidden-accessible')) {
+                    $(this).select2('close');
+                }
+            });
+            $('.filterDestinations').each(function() {
+                if ($(this).hasClass('select2-hidden-accessible')) {
+                    $(this).select2('close');
+                }
+            });
             $('.filterMember').each(function() {
                 if ($(this).hasClass('select2-hidden-accessible')) {
                     $(this).select2('close');
@@ -1432,6 +1460,80 @@
                     }, 100);
                 });
 
+                $(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);
+                });
+
+                if (!$('.filterOrigins').hasClass('select2-hidden-accessible')) {
+                    $('.filterOrigins').select2({
+                        "language": {"noResults": function(){return "Nessun risultato";}},
+                        "dropdownParent": $('body'),
+                        "width": "100%"
+                    });
+                }
+
+                $('.filterOrigins').off('change.customHandler').on('change.customHandler', function (e) {
+                    var data = $('.filterOrigins').select2("val");
+                    @this.set('filterOrigins', data);
+                });
+
+                $('.filterOrigins').off('select2:open.customHandler').on('select2:open.customHandler', function (e) {
+                    if ($('#causalsModal').hasClass('show')) {
+                        $('#causalsModal').modal('hide');
+                    }
+
+                    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);
+                });
+
+                if (!$('.filterDestinations').hasClass('select2-hidden-accessible')) {
+                    $('.filterDestinations').select2({
+                        "language": {"noResults": function(){return "Nessun risultato";}},
+                        "dropdownParent": $('body'),
+                        "width": "100%"
+                    });
+                }
+
+                $('.filterDestinations').off('change.customHandler').on('change.customHandler', function (e) {
+                    var data = $('.filterDestinations').select2("val");
+                    @this.set('filterDestinations', data);
+                });
+
+                $('.filterDestinations').off('select2:open.customHandler').on('select2:open.customHandler', function (e) {
+                    if ($('#causalsModal').hasClass('show')) {
+                        $('#causalsModal').modal('hide');
+                    }
+
+                    setTimeout(() => {
+                        $(".select2-results__option").each(function(){
+                            var txt = $(this).html();
+                            var count = (txt.match(/-/g) || []).length;
+                            $(this).addClass('paddingLeftSelect' + count);
+                        });
+                    }, 100);
+                });
+
                 if (!$('.filterMember').hasClass('select2-hidden-accessible')) {
                     $('.filterMember').select2({
                         "language": {"noResults": function(){return "Nessun risultato";}},
@@ -1570,6 +1672,8 @@
             $('.filterMember').val('').trigger('change');
             $('.filterCausals').val('').trigger('change');
             $('.filterPaymentMethods').val('').trigger('change');
+            $('.filterOrigins').val('').trigger('change');
+            $('.filterDestinations').val('').trigger('change');
             load();
         });
 
@@ -1899,6 +2003,8 @@
             $('.filterMember').val('').trigger('change');
             $('.filterCausals').val('').trigger('change');
             $('.filterPaymentMethods').val('').trigger('change');
+            $('.filterOrigins').val('').trigger('change');
+            $('.filterDestinations').val('').trigger('change');
 
             if (typeof @this !== 'undefined') {
                 @this.call('resetFilters');

+ 13 - 2
resources/views/livewire/records_in.blade.php

@@ -282,9 +282,12 @@
 
                             @if ($this->dataId > 0)
                                 <div class="row">
-                                    <div class="col-md-9 mt-3">
+                                    <div class="col-md-6 mt-3">
                                         {{$this->getPaymentMethod($payment_method_id)}}
                                     </div>
+                                    <div class="col-md-3 mt-3">
+                                        {{$this->getBankName($destination_id)}}
+                                    </div>
                                     <div class="col-md-3 mt-3">
                                         {{formatPrice($amount)}}
                                     </div>
@@ -293,9 +296,17 @@
                                 @foreach($payments as $payment)
                                     @if($payment->corrispettivo_fiscale)
                                         <div class="row">
-                                            <div class="col-md-9 mt-3">
+                                            <div class="col-md-6 mt-3">
                                                 {{$payment->name}}
                                             </div>
+                                            <div class="col-md-3 mt-3">                                                
+                                                <select id="corrispettivo_destination_{{$payment->id}}" name="corrispettivo_destination_{{$payment->id}}" wire:model="corrispettivo_destination.{{$payment->id}}" class="form-select" aria-label="Seleziona una destinazione" style="width:100%">
+                                                    <option value="">--Seleziona--
+                                                    @foreach($banks as $bank)
+                                                        <option value="{{$bank->id}}">{{$bank->name}}
+                                                    @endforeach
+                                                </select>
+                                            </div>
                                             <div class="col-md-3 mt-3">
                                                 <input type="text" class="form-control totalInput text-end" id="corrispettivo_{{$payment->id}}" wire:model="corrispettivo.{{$payment->id}}" onkeyup="onlyNumberAmount(this)" placeholder="€ 0,00">
                                             </div>

+ 1 - 1
resources/views/livewire/records_out.blade.php

@@ -50,7 +50,7 @@
                 <div class="col-md-2">
                     <div class="row">
                         <div class="col-md-12" style="margin-bottom:10px;">
-                            <b>Periodo</b>
+                            <b>Data pagamento</b>
                         </div>
                         <div class="col-12">
                             <input id="dateFrom" type="date" class="form-control filterFrom  mb-2"  >

+ 2 - 2
routes/web.php

@@ -1762,7 +1762,7 @@ Route::get('/send_sms', function () {
     $expire_date_it = date("d/m/Y", strtotime("+1 month"));
     $certificates = \App\Models\MemberCertificate::where('expire_date', $expire_date)->get();
     foreach ($certificates as $certificate) {
-        $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->count();
+        $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->where('member_id', $certificate->member_id)->count();
         if ($new == 0)
         {
             $phone = $certificate->member->phone;
@@ -1784,7 +1784,7 @@ Route::get('/send_sms', function () {
     $expire_date_it = date("d/m/Y", strtotime("+15 days"));
     $certificates = \App\Models\MemberCertificate::where('expire_date', $expire_date)->get();
     foreach ($certificates as $certificate) {
-        $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->count();
+        $new = \App\Models\MemberCertificate::where('expire_date', '>', $expire_date)->where('member_id', $certificate->member_id)->count();
         if ($new == 0)
         {
             $phone = $certificate->member->phone;