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.

BaseReportPage.php 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <?php
  2. namespace App\Filament\Company\Pages\Reports;
  3. use App\Contracts\ExportableReport;
  4. use App\DTO\ReportDTO;
  5. use App\Filament\Company\Pages\Concerns\HasDeferredFiltersForm;
  6. use App\Filament\Company\Pages\Concerns\HasToggleTableColumnForm;
  7. use App\Filament\Forms\Components\DateRangeSelect;
  8. use App\Models\Company;
  9. use App\Services\DateRangeService;
  10. use App\Support\Column;
  11. use Filament\Actions\Action;
  12. use Filament\Actions\ActionGroup;
  13. use Filament\Forms\Components\Component;
  14. use Filament\Forms\Components\DatePicker;
  15. use Filament\Forms\Form;
  16. use Filament\Forms\Set;
  17. use Filament\Pages\Page;
  18. use Filament\Support\Enums\IconPosition;
  19. use Filament\Support\Enums\IconSize;
  20. use Illuminate\Support\Carbon;
  21. use Livewire\Attributes\Computed;
  22. use Symfony\Component\HttpFoundation\StreamedResponse;
  23. abstract class BaseReportPage extends Page
  24. {
  25. use HasDeferredFiltersForm;
  26. use HasToggleTableColumnForm;
  27. public string $fiscalYearStartDate;
  28. public string $fiscalYearEndDate;
  29. public Company $company;
  30. public bool $reportLoaded = false;
  31. abstract protected function buildReport(array $columns): ReportDTO;
  32. abstract public function exportCSV(): StreamedResponse;
  33. abstract public function exportPDF(): StreamedResponse;
  34. abstract protected function getTransformer(ReportDTO $reportDTO): ExportableReport;
  35. /**
  36. * @return array<Column>
  37. */
  38. abstract public function getTable(): array;
  39. public function mount(): void
  40. {
  41. $this->initializeProperties();
  42. $this->loadDefaultDateRange();
  43. }
  44. protected function initializeProperties(): void
  45. {
  46. $this->company = auth()->user()->currentCompany;
  47. $this->fiscalYearStartDate = $this->company->locale->fiscalYearStartDate();
  48. $this->fiscalYearEndDate = $this->company->locale->fiscalYearEndDate();
  49. }
  50. protected function loadDefaultDateRange(): void
  51. {
  52. $startDate = $this->getFilterState('startDate');
  53. $endDate = $this->getFilterState('endDate');
  54. if ($this->isValidDate($startDate) && $this->isValidDate($endDate)) {
  55. $matchingDateRange = app(DateRangeService::class)->getMatchingDateRangeOption(Carbon::parse($startDate), Carbon::parse($endDate));
  56. $this->setFilterState('dateRange', $matchingDateRange);
  57. } else {
  58. $this->setFilterState('dateRange', $this->getDefaultDateRange());
  59. $this->setDateRange(Carbon::parse($this->fiscalYearStartDate), Carbon::parse($this->fiscalYearEndDate));
  60. }
  61. }
  62. public function loadReportData(): void
  63. {
  64. unset($this->report);
  65. $this->reportLoaded = true;
  66. }
  67. public function getDefaultDateRange(): string
  68. {
  69. return 'FY-' . now()->year;
  70. }
  71. #[Computed(persist: true)]
  72. public function report(): ?ExportableReport
  73. {
  74. if ($this->reportLoaded === false) {
  75. return null;
  76. }
  77. $columns = $this->getToggledColumns();
  78. $reportDTO = $this->buildReport($columns);
  79. return $this->getTransformer($reportDTO);
  80. }
  81. public function setDateRange(Carbon $start, Carbon $end): void
  82. {
  83. $this->setFilterState('startDate', $start->startOfDay()->toDateTimeString());
  84. $this->setFilterState('endDate', $end->isFuture() ? now()->endOfDay()->toDateTimeString() : $end->endOfDay()->toDateTimeString());
  85. }
  86. public function getFormattedStartDate(): string
  87. {
  88. return Carbon::parse($this->getFilterState('startDate'))->startOfDay()->toDateTimeString();
  89. }
  90. public function getFormattedEndDate(): string
  91. {
  92. return Carbon::parse($this->getFilterState('endDate'))->endOfDay()->toDateTimeString();
  93. }
  94. public function toggleTableColumnForm(Form $form): Form
  95. {
  96. return $form
  97. ->schema($this->getTableColumnToggleFormSchema());
  98. }
  99. protected function getHeaderActions(): array
  100. {
  101. return [
  102. ActionGroup::make([
  103. Action::make('exportCSV')
  104. ->label('CSV')
  105. ->action(fn () => $this->exportCSV()),
  106. Action::make('exportPDF')
  107. ->label('PDF')
  108. ->action(fn () => $this->exportPDF()),
  109. ])
  110. ->label('Export')
  111. ->button()
  112. ->outlined()
  113. ->dropdownWidth('max-w-[7rem]')
  114. ->dropdownPlacement('bottom-end')
  115. ->icon('heroicon-c-chevron-down')
  116. ->iconSize(IconSize::Small)
  117. ->iconPosition(IconPosition::After),
  118. ];
  119. }
  120. protected function getDateRangeFormComponent(): Component
  121. {
  122. return DateRangeSelect::make('dateRange')
  123. ->label('Date Range')
  124. ->selectablePlaceholder(false)
  125. ->startDateField('startDate')
  126. ->endDateField('endDate');
  127. }
  128. protected function getStartDateFormComponent(): Component
  129. {
  130. return DatePicker::make('startDate')
  131. ->label('Start Date')
  132. ->live()
  133. ->afterStateUpdated(static function ($state, Set $set) {
  134. $set('dateRange', 'Custom');
  135. });
  136. }
  137. protected function getEndDateFormComponent(): Component
  138. {
  139. return DatePicker::make('endDate')
  140. ->label('End Date')
  141. ->live()
  142. ->afterStateUpdated(static function (Set $set) {
  143. $set('dateRange', 'Custom');
  144. });
  145. }
  146. }