You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CompanyStatsOverview.php 3.2KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <?php
  2. namespace App\Filament\Pages\Widgets\Companies\Charts;
  3. use App\Models\Company;
  4. use Filament\Widgets\StatsOverviewWidget;
  5. class CompanyStatsOverview extends StatsOverviewWidget
  6. {
  7. protected int|string|array $columnSpan = 3;
  8. protected function getColumns(): int
  9. {
  10. return 3;
  11. }
  12. /**
  13. * Holt's Linear Trend
  14. */
  15. protected function holtLinearTrend($data, $alpha, $beta): array
  16. {
  17. $level = $data[0];
  18. $trend = $data[1] - $data[0];
  19. $forecast = [];
  20. for ($i = 0; $i < count($data); $i++) {
  21. $prev_level = $level;
  22. $level = $alpha * $data[$i] + (1 - $alpha) * ($prev_level + $trend);
  23. $trend = $beta * ($level - $prev_level) + (1 - $beta) * $trend;
  24. $forecast[] = $level + $trend;
  25. }
  26. return $forecast;
  27. }
  28. /**
  29. * Chart Options
  30. */
  31. protected function getCards(): array
  32. {
  33. // Define constants
  34. $alpha = 0.8;
  35. $beta = 0.2;
  36. // Define time variables
  37. $startOfYear = today()->startOfYear();
  38. $today = today();
  39. // Get Company Data
  40. $companyData = Company::selectRaw("COUNT(*) as aggregate, YEARWEEK(created_at, 3) as week")
  41. ->whereBetween('created_at', [$startOfYear, $today])
  42. ->groupByRaw('week')
  43. ->get();
  44. // Initialize weeks
  45. $weeks = [];
  46. for ($week = $startOfYear->copy(); $week->lte($today); $week->addWeek()) {
  47. $weeks[$week->format('oW')] = 0;
  48. }
  49. // Get Weekly Data
  50. $weeklyData = collect($weeks)->mapWithKeys(static function ($value, $week) use ($companyData) {
  51. $matchingData = $companyData->firstWhere('week', $week);
  52. return [$week => $matchingData ? $matchingData->aggregate : 0];
  53. });
  54. // Calculate total companies
  55. $totalCompanies = $weeklyData->reduce(static function ($carry, $value) {
  56. $carry[] = ($carry ? end($carry) : 0) + $value;
  57. return $carry;
  58. }, []);
  59. // Calculate new companies and percentage change
  60. $newCompanies = [0];
  61. $weeklyPercentageChange = [0];
  62. for ($i = 1; $i < count($totalCompanies); $i++) {
  63. $newCompanies[] = $totalCompanies[$i] - $totalCompanies[$i - 1];
  64. $weeklyPercentageChange[] = ($newCompanies[$i] / $totalCompanies[$i - 1]) * 100;
  65. }
  66. // Calculate average weekly growth rate
  67. $totalWeeks = $startOfYear->diffInWeeks($today);
  68. $averageWeeklyGrowthRate = round(array_sum($weeklyPercentageChange) / ($totalWeeks), 2);
  69. // Calculate Holt's forecast
  70. $weeklyDataArray = $weeklyData->values()->toArray();
  71. $holt_forecast = $this->holtLinearTrend($weeklyDataArray, $alpha, $beta);
  72. $expectedNewCompanies = round(end($holt_forecast));
  73. // Prepare cards for return
  74. return [
  75. StatsOverviewWidget\Card::make("New Companies Forecast (Holt's Trend)", $expectedNewCompanies),
  76. StatsOverviewWidget\Card::make('Average Weekly Growth Rate', $averageWeeklyGrowthRate . '%'),
  77. StatsOverviewWidget\Card::make('Personal Companies', Company::sum('personal_company')),
  78. ];
  79. }
  80. }