| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 | 
							- <?php
 - 
 - namespace App\Filament\Company\Pages\Reports;
 - 
 - use App\Contracts\ExportableReport;
 - use App\DTO\ReportDTO;
 - use App\Filament\Company\Pages\Concerns\HasDeferredFiltersForm;
 - use App\Filament\Company\Pages\Concerns\HasTableColumnToggleForm;
 - use App\Filament\Company\Pages\Reports;
 - use App\Filament\Forms\Components\DateRangeSelect;
 - use App\Models\Company;
 - use App\Services\CompanySettingsService;
 - use App\Services\DateRangeService;
 - use App\Support\Column;
 - use Filament\Actions\Action;
 - use Filament\Actions\ActionGroup;
 - use Filament\Forms\Components\DatePicker;
 - use Filament\Forms\Set;
 - use Filament\Pages\Page;
 - use Filament\Support\Enums\IconPosition;
 - use Illuminate\Support\Arr;
 - use Illuminate\Support\Carbon;
 - use Livewire\Attributes\Computed;
 - use Symfony\Component\HttpFoundation\StreamedResponse;
 - 
 - abstract class BaseReportPage extends Page
 - {
 -     use HasDeferredFiltersForm;
 -     use HasTableColumnToggleForm;
 - 
 -     public string $fiscalYearStartDate;
 - 
 -     public string $fiscalYearEndDate;
 - 
 -     public Company $company;
 - 
 -     public bool $reportLoaded = false;
 - 
 -     abstract protected function buildReport(array $columns): ReportDTO;
 - 
 -     abstract public function exportCSV(): StreamedResponse;
 - 
 -     abstract public function exportPDF(): StreamedResponse;
 - 
 -     abstract protected function getTransformer(ReportDTO $reportDTO): ExportableReport;
 - 
 -     /**
 -      * @return array<Column>
 -      */
 -     abstract public function getTable(): array;
 - 
 -     public function mount(): void
 -     {
 -         $this->initializeProperties();
 - 
 -         $this->loadDefaultDateRange();
 -     }
 - 
 -     protected function initializeProperties(): void
 -     {
 -         $this->company = auth()->user()->currentCompany;
 -         $this->fiscalYearStartDate = $this->company->locale->fiscalYearStartDate();
 -         $this->fiscalYearEndDate = $this->company->locale->fiscalYearEndDate();
 -     }
 - 
 -     public static function shouldRegisterNavigation(): bool
 -     {
 -         return false;
 -     }
 - 
 -     public static function getSlug(): string
 -     {
 -         $prefix = Reports::getSlug() . '/';
 - 
 -         if (filled(static::$slug)) {
 -             return $prefix . static::$slug;
 -         }
 - 
 -         return $prefix . str(class_basename(static::class))
 -             ->kebab()
 -             ->slug();
 -     }
 - 
 -     public function getBreadcrumbs(): array
 -     {
 -         return [
 -             Reports::getUrl() => Reports::getNavigationLabel(),
 -         ];
 -     }
 - 
 -     protected function loadDefaultDateRange(): void
 -     {
 -         $flatFields = $this->getFiltersForm()->getFlatFields();
 - 
 -         $dateRangeField = Arr::first($flatFields, static fn ($field) => $field instanceof DateRangeSelect);
 - 
 -         if (! $dateRangeField) {
 -             return;
 -         }
 - 
 -         $startDateField = $dateRangeField->getStartDateField();
 -         $endDateField = $dateRangeField->getEndDateField();
 - 
 -         $startDate = $startDateField ? $this->getFilterState($startDateField) : null;
 -         $endDate = $endDateField ? $this->getFilterState($endDateField) : null;
 - 
 -         $startDateCarbon = $this->isValidDate($startDate) ? Carbon::parse($startDate) : null;
 -         $endDateCarbon = $this->isValidDate($endDate) ? Carbon::parse($endDate) : null;
 - 
 -         if ($startDateCarbon && $endDateCarbon) {
 -             $this->setMatchingDateRange($startDateCarbon, $endDateCarbon);
 - 
 -             return;
 -         }
 - 
 -         if ($endDateCarbon && ! $startDateField) {
 -             $this->setAsOfDateRange($endDateCarbon);
 - 
 -             return;
 -         }
 - 
 -         if ($endDateField && ! $startDateField) {
 -             $this->setFilterState('dateRange', $this->getDefaultDateRange());
 -             $defaultEndDate = Carbon::parse($this->fiscalYearEndDate);
 -             $this->setFilterState($endDateField, $defaultEndDate->isFuture() ? now()->endOfDay()->toDateTimeString() : $defaultEndDate->endOfDay()->toDateTimeString());
 - 
 -             return;
 -         }
 - 
 -         if ($startDateField && $endDateField) {
 -             $this->setFilterState('dateRange', $this->getDefaultDateRange());
 -             $defaultStartDate = Carbon::parse($this->fiscalYearStartDate);
 -             $defaultEndDate = Carbon::parse($this->fiscalYearEndDate);
 -             $this->setDateRange($defaultStartDate, $defaultEndDate);
 -         }
 -     }
 - 
 -     protected function setMatchingDateRange($startDate, $endDate): void
 -     {
 -         $matchingDateRange = app(DateRangeService::class)->getMatchingDateRangeOption($startDate, $endDate);
 -         $this->setFilterState('dateRange', $matchingDateRange);
 -     }
 - 
 -     protected function setAsOfDateRange($endDate): void
 -     {
 -         $fiscalYearStart = Carbon::parse($this->fiscalYearStartDate);
 -         $asOfStartDate = $endDate->copy()->setMonth($fiscalYearStart->month)->setDay($fiscalYearStart->day);
 - 
 -         $this->setMatchingDateRange($asOfStartDate, $endDate);
 -     }
 - 
 -     public function loadReportData(): void
 -     {
 -         unset($this->report);
 - 
 -         $this->reportLoaded = true;
 -     }
 - 
 -     public function getDefaultDateRange(): string
 -     {
 -         return 'FY-' . now()->year;
 -     }
 - 
 -     #[Computed(persist: true)]
 -     public function report(): ?ExportableReport
 -     {
 -         if ($this->reportLoaded === false) {
 -             return null;
 -         }
 - 
 -         $columns = $this->getToggledColumns();
 -         $reportDTO = $this->buildReport($columns);
 - 
 -         return $this->getTransformer($reportDTO);
 -     }
 - 
 -     public function setDateRange(Carbon $start, Carbon $end): void
 -     {
 -         $this->setFilterState('startDate', $start->startOfDay()->toDateTimeString());
 -         $this->setFilterState('endDate', $end->isFuture() ? now()->endOfDay()->toDateTimeString() : $end->endOfDay()->toDateTimeString());
 -     }
 - 
 -     public function getFormattedStartDate(): string
 -     {
 -         return Carbon::parse($this->getFilterState('startDate'))->startOfDay()->toDateTimeString();
 -     }
 - 
 -     public function getFormattedEndDate(): string
 -     {
 -         return Carbon::parse($this->getFilterState('endDate'))->endOfDay()->toDateTimeString();
 -     }
 - 
 -     public function getFormattedAsOfDate(): string
 -     {
 -         return Carbon::parse($this->getFilterState('asOfDate'))->endOfDay()->toDateTimeString();
 -     }
 - 
 -     public function getDisplayAsOfDate(): string
 -     {
 -         return Carbon::parse($this->getFilterState('asOfDate'))->toDefaultDateFormat();
 -     }
 - 
 -     public function getDisplayStartDate(): string
 -     {
 -         return Carbon::parse($this->getFilterState('startDate'))->toDefaultDateFormat();
 -     }
 - 
 -     public function getDisplayEndDate(): string
 -     {
 -         return Carbon::parse($this->getFilterState('endDate'))->toDefaultDateFormat();
 -     }
 - 
 -     public function getDisplayDateRange(): string
 -     {
 -         $startDate = Carbon::parse($this->getFilterState('startDate'));
 -         $endDate = Carbon::parse($this->getFilterState('endDate'));
 - 
 -         return $startDate->toDefaultDateFormat() . ' - ' . $endDate->toDefaultDateFormat();
 -     }
 - 
 -     protected function getHeaderActions(): array
 -     {
 -         return [
 -             ActionGroup::make([
 -                 Action::make('exportCSV')
 -                     ->label('CSV')
 -                     ->action(fn () => $this->exportCSV()),
 -                 Action::make('exportPDF')
 -                     ->label('PDF')
 -                     ->hidden(is_demo_environment())
 -                     ->action(fn () => $this->exportPDF()),
 -             ])
 -                 ->label('Export')
 -                 ->button()
 -                 ->outlined()
 -                 ->dropdownWidth('max-w-[7rem]')
 -                 ->dropdownPlacement('bottom-end')
 -                 ->icon('heroicon-m-chevron-down')
 -                 ->iconPosition(IconPosition::After),
 -         ];
 -     }
 - 
 -     protected function getDateRangeFormComponent(): DateRangeSelect
 -     {
 -         return DateRangeSelect::make('dateRange')
 -             ->label('Date range')
 -             ->selectablePlaceholder(false)
 -             ->startDateField('startDate')
 -             ->endDateField('endDate');
 -     }
 - 
 -     protected function getStartDateFormComponent(): DatePicker
 -     {
 -         return DatePicker::make('startDate')
 -             ->label('Start date')
 -             ->live()
 -             ->timezone(CompanySettingsService::getDefaultTimezone())
 -             ->afterStateUpdated(static function ($state, Set $set) {
 -                 $set('dateRange', 'Custom');
 -             });
 -     }
 - 
 -     protected function getEndDateFormComponent(): DatePicker
 -     {
 -         return DatePicker::make('endDate')
 -             ->label('End date')
 -             ->live()
 -             ->timezone(CompanySettingsService::getDefaultTimezone())
 -             ->afterStateUpdated(static function (Set $set) {
 -                 $set('dateRange', 'Custom');
 -             });
 -     }
 - 
 -     protected function getAsOfDateFormComponent(): DatePicker
 -     {
 -         return DatePicker::make('asOfDate')
 -             ->label('As of date')
 -             ->live()
 -             ->afterStateUpdated(static function (Set $set) {
 -                 $set('dateRange', 'Custom');
 -             })
 -             ->extraFieldWrapperAttributes([
 -                 'class' => 'report-hidden-label',
 -             ]);
 -     }
 - }
 
 
  |