Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

AccountBalances.php 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <?php
  2. namespace App\Filament\Company\Pages\Reports;
  3. use App\DTO\AccountBalanceReportDTO;
  4. use App\Models\Company;
  5. use App\Services\AccountBalancesExportService;
  6. use App\Services\AccountService;
  7. use Barryvdh\DomPDF\Facade\Pdf;
  8. use Carbon\CarbonPeriod;
  9. use Filament\Actions\Action;
  10. use Filament\Actions\ActionGroup;
  11. use Filament\Forms\Components\DatePicker;
  12. use Filament\Forms\Components\Select;
  13. use Filament\Forms\Components\Split;
  14. use Filament\Forms\Form;
  15. use Filament\Forms\Set;
  16. use Filament\Pages\Page;
  17. use Filament\Support\Enums\IconPosition;
  18. use Filament\Support\Enums\IconSize;
  19. use Illuminate\Support\Carbon;
  20. use Symfony\Component\HttpFoundation\StreamedResponse;
  21. class AccountBalances extends Page
  22. {
  23. protected static string $view = 'filament.company.pages.reports.account-balances';
  24. protected static ?string $slug = 'reports/account-balances';
  25. public string $startDate = '';
  26. public string $endDate = '';
  27. public string $dateRange = '';
  28. public string $fiscalYearStartDate = '';
  29. public string $fiscalYearEndDate = '';
  30. public Company $company;
  31. public AccountBalanceReportDTO $accountBalanceReport;
  32. protected AccountService $accountService;
  33. protected AccountBalancesExportService $accountBalancesExportService;
  34. public function boot(AccountService $accountService, AccountBalancesExportService $accountBalancesExportService): void
  35. {
  36. $this->accountService = $accountService;
  37. $this->accountBalancesExportService = $accountBalancesExportService;
  38. }
  39. public function mount(): void
  40. {
  41. $this->company = auth()->user()->currentCompany;
  42. $this->fiscalYearStartDate = $this->company->locale->fiscalYearStartDate();
  43. $this->fiscalYearEndDate = $this->company->locale->fiscalYearEndDate();
  44. $this->dateRange = $this->getDefaultDateRange();
  45. $this->updateDateRange($this->dateRange);
  46. $this->loadAccountBalances();
  47. }
  48. public function getDefaultDateRange(): string
  49. {
  50. return 'FY-' . now()->year;
  51. }
  52. public function loadAccountBalances(): void
  53. {
  54. $startTime = microtime(true);
  55. $this->accountBalanceReport = $this->accountService->buildAccountBalanceReport($this->startDate, $this->endDate);
  56. $endTime = microtime(true);
  57. $executionTime = ($endTime - $startTime);
  58. info('Account balance report loaded in ' . $executionTime . ' seconds');
  59. }
  60. protected function getHeaderActions(): array
  61. {
  62. return [
  63. ActionGroup::make([
  64. Action::make('exportCSV')
  65. ->label('CSV')
  66. ->action(fn () => $this->exportCSV()),
  67. Action::make('exportPDF')
  68. ->label('PDF')
  69. ->action(fn () => $this->exportPDF()),
  70. ])
  71. ->label('Export')
  72. ->button()
  73. ->outlined()
  74. ->dropdownWidth('max-w-[7rem]')
  75. ->dropdownPlacement('bottom-end')
  76. ->icon('heroicon-c-chevron-down')
  77. ->iconSize(IconSize::Small)
  78. ->iconPosition(IconPosition::After),
  79. ];
  80. }
  81. public function exportCSV(): StreamedResponse
  82. {
  83. return $this->accountBalancesExportService->exportToCsv($this->company, $this->accountBalanceReport, $this->startDate, $this->endDate);
  84. }
  85. public function exportPDF(): StreamedResponse
  86. {
  87. $pdf = Pdf::loadView('components.company.reports.account-balances', [
  88. 'accountBalanceReport' => $this->accountBalanceReport,
  89. 'startDate' => Carbon::parse($this->startDate)->format('M d, Y'),
  90. 'endDate' => Carbon::parse($this->endDate)->format('M d, Y'),
  91. ])->setPaper('a4')->setOption(['defaultFont' => 'sans-serif', 'isPhpEnabled' => true]);
  92. return response()->streamDownload(function () use ($pdf) {
  93. echo $pdf->stream();
  94. }, 'account-balances.pdf');
  95. }
  96. public function form(Form $form): Form
  97. {
  98. return $form
  99. ->schema([
  100. Split::make([
  101. Select::make('dateRange')
  102. ->label('Date Range')
  103. ->options($this->getDateRangeOptions())
  104. ->selectablePlaceholder(false)
  105. ->afterStateUpdated(function ($state) {
  106. $this->updateDateRange($state);
  107. }),
  108. DatePicker::make('startDate')
  109. ->label('Start Date')
  110. ->displayFormat('Y-m-d')
  111. ->afterStateUpdated(static function (Set $set) {
  112. $set('dateRange', 'Custom');
  113. }),
  114. DatePicker::make('endDate')
  115. ->label('End Date')
  116. ->displayFormat('Y-m-d')
  117. ->afterStateUpdated(static function (Set $set) {
  118. $set('dateRange', 'Custom');
  119. }),
  120. ])->live(),
  121. ]);
  122. }
  123. public function getDateRangeOptions(): array
  124. {
  125. $earliestDate = Carbon::parse($this->accountService->getEarliestTransactionDate());
  126. $currentDate = now();
  127. $fiscalYearStartCurrent = Carbon::parse($this->fiscalYearStartDate);
  128. $options = [
  129. 'Fiscal Year' => [],
  130. 'Fiscal Quarter' => [],
  131. 'Calendar Year' => [],
  132. 'Calendar Quarter' => [],
  133. 'Month' => [],
  134. 'Custom' => [],
  135. ];
  136. $period = CarbonPeriod::create($earliestDate, '1 month', $currentDate);
  137. foreach ($period as $date) {
  138. $options['Fiscal Year']['FY-' . $date->year] = $date->year;
  139. $fiscalYearStart = $fiscalYearStartCurrent->copy()->subYears($currentDate->year - $date->year);
  140. for ($i = 0; $i < 4; $i++) {
  141. $quarterNumber = $i + 1;
  142. $quarterStart = $fiscalYearStart->copy()->addMonths(($quarterNumber - 1) * 3);
  143. $quarterEnd = $quarterStart->copy()->addMonths(3)->subDay();
  144. if ($quarterStart->lessThanOrEqualTo($currentDate) && $quarterEnd->greaterThanOrEqualTo($earliestDate)) {
  145. $options['Fiscal Quarter']['FQ-' . $quarterNumber . '-' . $date->year] = 'Q' . $quarterNumber . ' ' . $date->year;
  146. }
  147. }
  148. $options['Calendar Year']['Y-' . $date->year] = $date->year;
  149. $quarterKey = 'Q-' . $date->quarter . '-' . $date->year;
  150. $options['Calendar Quarter'][$quarterKey] = 'Q' . $date->quarter . ' ' . $date->year;
  151. $options['Month']['M-' . $date->format('Y-m')] = $date->format('F Y');
  152. $options['Custom']['Custom'] = 'Custom';
  153. }
  154. $options['Fiscal Year'] = array_reverse($options['Fiscal Year'], true);
  155. $options['Fiscal Quarter'] = array_reverse($options['Fiscal Quarter'], true);
  156. $options['Calendar Year'] = array_reverse($options['Calendar Year'], true);
  157. $options['Calendar Quarter'] = array_reverse($options['Calendar Quarter'], true);
  158. $options['Month'] = array_reverse($options['Month'], true);
  159. return $options;
  160. }
  161. public function updateDateRange($state): void
  162. {
  163. [$type, $param1, $param2] = explode('-', $state) + [null, null, null];
  164. $this->processDateRange($type, $param1, $param2);
  165. }
  166. public function processDateRange($type, $param1, $param2): void
  167. {
  168. match ($type) {
  169. 'FY' => $this->processFiscalYear($param1),
  170. 'FQ' => $this->processFiscalQuarter($param1, $param2),
  171. 'Y' => $this->processCalendarYear($param1),
  172. 'Q' => $this->processCalendarQuarter($param1, $param2),
  173. 'M' => $this->processMonth("{$param1}-{$param2}"),
  174. };
  175. }
  176. public function processFiscalYear($year): void
  177. {
  178. $currentYear = now()->year;
  179. $diff = $currentYear - $year;
  180. $fiscalYearStart = Carbon::parse($this->fiscalYearStartDate)->subYears($diff);
  181. $fiscalYearEnd = Carbon::parse($this->fiscalYearEndDate)->subYears($diff);
  182. $this->setDateRange($fiscalYearStart, $fiscalYearEnd);
  183. }
  184. public function processFiscalQuarter($quarter, $year): void
  185. {
  186. $currentYear = now()->year;
  187. $diff = $currentYear - $year;
  188. $fiscalYearStart = Carbon::parse($this->company->locale->fiscal_year_start_date)->subYears($diff);
  189. $quarterStart = $fiscalYearStart->copy()->addMonths(($quarter - 1) * 3);
  190. $quarterEnd = $quarterStart->copy()->addMonths(3)->subDay();
  191. $this->setDateRange($quarterStart, $quarterEnd);
  192. }
  193. public function processCalendarYear($year): void
  194. {
  195. $start = Carbon::createFromDate($year)->startOfYear();
  196. $end = Carbon::createFromDate($year)->endOfYear();
  197. $this->setDateRange($start, $end);
  198. }
  199. public function processCalendarQuarter($quarter, $year): void
  200. {
  201. $month = ($quarter - 1) * 3 + 1;
  202. $start = Carbon::createFromDate($year, $month, 1);
  203. $end = Carbon::createFromDate($year, $month, 1)->endOfQuarter();
  204. $this->setDateRange($start, $end);
  205. }
  206. public function processMonth($yearMonth): void
  207. {
  208. $start = Carbon::parse($yearMonth)->startOfMonth();
  209. $end = Carbon::parse($yearMonth)->endOfMonth();
  210. $this->setDateRange($start, $end);
  211. }
  212. public function setDateRange(Carbon $start, Carbon $end): void
  213. {
  214. $this->startDate = $start->format('Y-m-d');
  215. $this->endDate = $end->isFuture() ? now()->format('Y-m-d') : $end->format('Y-m-d');
  216. }
  217. public static function shouldRegisterNavigation(): bool
  218. {
  219. return false;
  220. }
  221. }