| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- <?php
- namespace App\Http\Livewire;
- use Livewire\Component;
- use Illuminate\Support\Facades\Auth;
- use Carbon\Carbon;
- use App\Models\Receipt;
- use App\Models\ReceiptRow;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use App\Models\Course;
- use App\Models\MemberCard;
- class Reports extends Component
- {
- public $type = 'anagrafica';
- public $yearFilter;
- public $courses = [];
- public $selectedCourse = null;
- protected $listeners = ['refreshData' => '$refresh'];
- public function mount()
- {
- if (Auth::user()->level != env('LEVEL_ADMIN', 0))
- return redirect()->to('/reports');
- if (isset($_GET["type"]))
- $this->type = $_GET["type"];
- $this->yearFilter = Carbon::now()->year;
- $this->courses = $this->getCoursesForSelect();
- $this->emit('dataUpdated');
- }
- public function render()
- {
- return view('livewire.reports');
- }
- public function updateCourseChart()
- {
- $this->emit('courseDataUpdated');
- }
- public function updatedSelectedCourse($value)
- {
- Log::info('Selected course changed to: ' . $value);
- $this->emit('courseDataUpdated', $value);
- }
- public function getTesseratiData()
- {
- $endYear = $this->yearFilter;
- return self::getMemberCountChartData($endYear);
- }
- public function change($type)
- {
- $this->type = $type;
- }
- public function setYearFilter($year)
- {
- $this->yearFilter = $year;
- $this->emit('dataUpdated');
- }
- public function getMonthlyTotals()
- {
- $year = $this->yearFilter;
- $months = range(1, 12);
- $monthNames = [];
- $incomeData = array_fill(0, 12, 0);
- $expenseData = array_fill(0, 12, 0);
- foreach ($months as $month) {
- $date = Carbon::createFromDate($year, $month, 1);
- $monthNames[] = ucfirst($date->locale('it')->monthName);
- }
- $incomeReceipts = DB::table('receipts')
- ->join('receipts_rows', 'receipts.id', '=', 'receipts_rows.receip_id')
- ->where('receipts.year', $year)
- ->where('receipts.type', 'IN')
- ->select(DB::raw('MONTH(receipts.date) as month_num'), DB::raw('SUM(receipts_rows.amount) as total'))
- ->groupBy('month_num')
- ->get();
- $expenseReceipts = DB::table('receipts')
- ->join('receipts_rows', 'receipts.id', '=', 'receipts_rows.receip_id')
- ->where('receipts.year', $year)
- ->where('receipts.type', 'OUT')
- ->select(DB::raw('MONTH(receipts.date) as month_num'), DB::raw('SUM(receipts_rows.amount) as total'))
- ->groupBy('month_num')
- ->get();
- foreach ($incomeReceipts as $receipt) {
- $index = $receipt->month_num - 1;
- if (isset($incomeData[$index])) {
- $incomeData[$index] = $receipt->total;
- }
- }
- foreach ($expenseReceipts as $receipt) {
- $index = $receipt->month_num - 1;
- if (isset($expenseData[$index])) {
- $expenseData[$index] = $receipt->total;
- }
- }
- return [
- 'labels' => $monthNames,
- 'datasets' => [
- [
- 'label' => 'Entrate',
- 'data' => $incomeData,
- 'backgroundColor' => 'rgba(54, 162, 235, 0.5)'
- ],
- [
- 'label' => 'Uscite',
- 'data' => $expenseData,
- 'backgroundColor' => 'rgba(255, 99, 132, 0.5)'
- ],
- ]
- ];
- }
- public function getYearlySummary()
- {
- $year = $this->yearFilter;
- $totalIncome = DB::table('receipts')
- ->join('receipts_rows', 'receipts.id', '=', 'receipts_rows.receip_id')
- ->where('receipts.year', $year)
- ->where('receipts.type', 'IN')
- ->sum('receipts_rows.amount');
- $totalExpenses = DB::table('receipts')
- ->join('receipts_rows', 'receipts.id', '=', 'receipts_rows.receip_id')
- ->where('receipts.year', $year)
- ->where('receipts.type', 'OUT')
- ->sum('receipts_rows.amount');
- $delta = $totalIncome - $totalExpenses;
- return [
- 'totalIncome' => $totalIncome,
- 'totalExpenses' => $totalExpenses,
- 'delta' => $delta
- ];
- }
- public function getTopCausalsByAmount($limit = 10)
- {
- $year = $this->yearFilter;
- $query = DB::table('receipts_rows')
- ->join('receipts', 'receipts_rows.receip_id', '=', 'receipts.id')
- ->join('causals', 'receipts_rows.causal_id', '=', 'causals.id')
- ->where('receipts.year', $year);
- $query->where('receipts.type', 'IN');
- Log::info('Query: ' . $query->toSql());
- $causals = $query->select(
- 'causals.id',
- 'causals.name',
- 'causals.parent_id',
- DB::raw('SUM(receipts_rows.amount) as total_amount')
- )
- ->groupBy('causals.id', 'causals.name', 'causals.parent_id')
- ->orderBy('total_amount', 'desc')
- ->limit($limit)
- ->get();
- Log::info('Causals: ' . json_encode($causals));
- $inData = [];
- foreach ($causals as $causal) {
- $tempCausal = new \App\Models\Causal();
- $tempCausal->id = $causal->id;
- $tempCausal->name = $causal->name;
- $tempCausal->parent_id = $causal->parent_id;
- $treeName = $tempCausal->getTree();
- $displayName = strlen($treeName) > 30 ? substr($treeName, 0, 27) . '...' : $treeName;
- $inData[] = [
- 'label' => $displayName,
- 'value' => $causal->total_amount,
- 'fullName' => $treeName
- ];
- }
- usort($inData, function ($a, $b) {
- return $b['value'] <=> $a['value'];
- });
- $inData = array_slice($inData, 0, $limit);
- return [
- 'inLabels' => array_column($inData, 'label'),
- 'inData' => $inData,
- 'datasets' => [
- [
- 'label' => 'Entrate per Causale',
- 'data' => array_column($inData, 'value'),
- ]
- ]
- ];
- }
- public function getCoursesForSelect()
- {
- $currentYear = date('Y');
- $courses = Course::with(['level', 'type', 'frequency'])
- ->where('active', true)
- ->where('year', 'like', '%' . $currentYear . '%')
- ->orderBy('name')
- ->get()
- ->map(function ($course) {
- if (!empty($course->course_type_id)) {
- $type = \App\Models\CourseType::find($course->course_type_id);
- if ($type) {
- $typeName = $type->name;
- }
- }
- $levelName = is_object($course->level) ? $course->level->name : 'No Level';
- $typeName = is_object($type) ? $type->name : 'No Type';
- $frequencyName = is_object($course->frequency) ? $course->frequency->name : 'No Frequency';
- $year = $course->year ?? '';
- return [
- 'id' => $course->id,
- 'name' => $course->name,
- 'full_name' => "{$course->name} - {$levelName} - {$typeName} - {$frequencyName} ({$year})",
- 'level_name' => $levelName,
- 'type_name' => $typeName,
- 'frequency_name' => $frequencyName,
- 'year' => $year
- ];
- })->toArray();
- return $courses;
- }
- public function getCourseMonthlyEarnings()
- {
- $courseId = $this->selectedCourse;
- Log::info('Getting earnings for course ID: ' . $courseId);
- if (empty($courseId)) {
- return [
- 'labels' => ['Set', 'Ott', 'Nov', 'Dic', 'Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago'],
- 'datasets' => [
- [
- 'label' => 'Pagamenti Effettuati',
- 'backgroundColor' => 'rgba(0, 184, 148, 1)',
- 'data' => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- 'type' => 'bar',
- 'order' => 3
- ],
- [
- 'label' => 'Pagamenti Totali',
- 'backgroundColor' => 'transparent',
- 'borderColor' => 'rgba(48, 51, 107, 1)',
- 'borderWidth' => 3,
- 'pointBackgroundColor' => 'rgba(48, 51, 107, 1)',
- 'pointRadius' => 5,
- 'data' => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- 'type' => 'line',
- 'tension' => 0.2,
- 'order' => 2
- ]
- ]
- ];
- }
- $monthOrder = [9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8];
- $monthlyData = [];
- foreach ($monthOrder as $i) {
- $monthlyData[$i] = [
- 'earned' => 0,
- 'total' => 0,
- 'participants' => 0
- ];
- }
- $memberCourses = \App\Models\MemberCourse::where('course_id', $courseId)
- ->with('member')
- ->get();
- foreach ($memberCourses as $memberCourse) {
- $price = (float)($memberCourse->price ?? 0);
- if ($memberCourse->months) {
- $monthsData = json_decode($memberCourse->months, true);
- if (is_array($monthsData)) {
- foreach ($monthsData as $monthData) {
- $month = $monthData['m'] ?? null;
- $status = $monthData['status'] ?? '';
- if ($month !== null && isset($monthlyData[$month])) {
- $monthlyData[$month]['total'] += $price;
- if ($status === 1) {
- $monthlyData[$month]['earned'] += $price;
- }
- $monthlyData[$month]['participants']++;
- }
- }
- }
- }
- }
- $monthNames = [
- 9 => 'Set',
- 10 => 'Ott',
- 11 => 'Nov',
- 12 => 'Dic',
- 1 => 'Gen',
- 2 => 'Feb',
- 3 => 'Mar',
- 4 => 'Apr',
- 5 => 'Mag',
- 6 => 'Giu',
- 7 => 'Lug',
- 8 => 'Ago',
- ];
- $labels = [];
- $earnedData = [];
- $totalData = [];
- $participantData = [];
- $missingData = [];
- foreach ($monthOrder as $month) {
- $labels[] = $monthNames[$month];
- $earnedData[] = round($monthlyData[$month]['earned'], 2);
- $totalData[] = round($monthlyData[$month]['total'], 2);
- $participantData[] = $monthlyData[$month]['participants'];
- $missingData[] = round($monthlyData[$month]['total'] - $monthlyData[$month]['earned'], 2);
- }
- return [
- 'labels' => $labels,
- 'datasets' => [
- [
- 'label' => 'Pagamenti Effettuati',
- 'backgroundColor' => 'rgba(0, 184, 148, 1)',
- 'data' => $earnedData,
- 'type' => 'bar',
- 'order' => 3
- ],
- [
- 'label' => 'Pagamenti Attesi',
- 'backgroundColor' => 'transparent',
- 'borderColor' => 'rgba(48, 51, 107, 1)',
- 'borderWidth' => 3,
- 'pointBackgroundColor' => 'rgba(48, 51, 107, 1)',
- 'pointRadius' => 5,
- 'data' => $totalData,
- 'type' => 'line',
- 'tension' => 0.2,
- 'order' => 2,
- 'participants' => $participantData,
- 'missing' => $missingData
- ]
- ]
- ];
- }
- public static function getMemberCountChartData($endYear = null, $span = 5)
- {
- if ($endYear === null) {
- $endYear = date('Y');
- }
- $startYear = $endYear - $span + 1;
- $memberCards = MemberCard::select('member_id', 'expire_date')
- ->whereNotNull('expire_date')
- ->whereNotNull('member_id')
- ->where('status', '!=', 'cancelled')
- ->whereRaw('YEAR(expire_date) >= ?', [$startYear])
- ->whereRaw('YEAR(expire_date) <= ?', [$endYear])
- ->get();
- $yearCounts = [];
- for ($year = $startYear; $year <= $endYear; $year++) {
- $yearPeriod = ($year - 1) . '-' . $year;
- $yearCounts[$yearPeriod] = [];
- }
- foreach ($memberCards as $card) {
- $expireYear = date('Y', strtotime($card->expire_date));
- $previousYear = $expireYear - 1;
- $yearPeriod = $previousYear . '-' . $expireYear;
- if (isset($yearCounts[$yearPeriod])) {
- $yearCounts[$yearPeriod][$card->member_id] = true;
- }
- }
- $yearLabels = [];
- $memberCountData = [];
- foreach ($yearCounts as $yearPeriod => $members) {
- $yearLabels[] = $yearPeriod;
- $memberCountData[] = count($members);
- }
- return [
- 'labels' => $yearLabels,
- 'datasets' => [
- [
- 'label' => 'Membri Tesserati',
- 'data' => $memberCountData,
- 'backgroundColor' => 'rgba(54, 162, 235, 0.2)',
- 'borderColor' => 'rgba(54, 162, 235, 1)',
- 'borderWidth' => 2,
- 'pointBackgroundColor' => 'rgba(54, 162, 235, 1)',
- 'pointRadius' => 4,
- 'tension' => 0.3,
- 'fill' => true
- ]
- ]
- ];
- }
- }
|