Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

AccountChart.php 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. namespace App\Filament\Company\Pages\Accounting;
  3. use App\Enums\Accounting\AccountCategory;
  4. use App\Models\Accounting\Account as ChartModel;
  5. use App\Models\Accounting\AccountSubtype;
  6. use App\Utilities\Accounting\AccountCode;
  7. use App\Utilities\Currency\CurrencyAccessor;
  8. use Filament\Actions\Action;
  9. use Filament\Actions\CreateAction;
  10. use Filament\Actions\EditAction;
  11. use Filament\Forms\Components\Select;
  12. use Filament\Forms\Components\Textarea;
  13. use Filament\Forms\Components\TextInput;
  14. use Filament\Forms\Form;
  15. use Filament\Forms\Get;
  16. use Filament\Forms\Set;
  17. use Filament\Pages\Page;
  18. use Filament\Support\Enums\MaxWidth;
  19. use Illuminate\Support\Collection;
  20. use Livewire\Attributes\Computed;
  21. use Livewire\Attributes\Url;
  22. class AccountChart extends Page
  23. {
  24. protected static ?string $title = 'Chart of Accounts';
  25. protected static ?string $slug = 'accounting/chart';
  26. protected static string $view = 'filament.company.pages.accounting.chart';
  27. public ?ChartModel $chart = null;
  28. #[Url]
  29. public ?string $activeTab = null;
  30. public function mount(): void
  31. {
  32. $this->activeTab = $this->activeTab ?? AccountCategory::Asset->value;
  33. }
  34. protected function configureAction(Action $action): void
  35. {
  36. $action
  37. ->modalWidth(MaxWidth::TwoExtraLarge)
  38. ->stickyModalHeader()
  39. ->stickyModalFooter();
  40. }
  41. #[Computed]
  42. public function categories(): Collection
  43. {
  44. return AccountSubtype::withCount('accounts')
  45. ->get()
  46. ->groupBy('category');
  47. }
  48. public function editChartAction(): Action
  49. {
  50. return EditAction::make()
  51. ->iconButton()
  52. ->record($this->chart)
  53. ->name('editChart')
  54. ->label('Edit account')
  55. ->modalHeading('Edit Account')
  56. ->icon('heroicon-m-pencil-square')
  57. ->mountUsing(function (array $arguments, Form $form) {
  58. $chartId = $arguments['chart'];
  59. $this->chart = ChartModel::find($chartId);
  60. $form
  61. ->fill($this->chart->toArray())
  62. ->operation('edit')
  63. ->model($this->chart); // This is needed for form relationships to work (maybe a bug in Filament regarding passed arguments related to timing)
  64. })
  65. ->form($this->getChartForm());
  66. }
  67. public function createChartAction(): Action
  68. {
  69. return CreateAction::make()
  70. ->link()
  71. ->name('createChart')
  72. ->form($this->getChartForm())
  73. ->model(ChartModel::class)
  74. ->label('Add a new account')
  75. ->icon('heroicon-o-plus-circle')
  76. ->mountUsing(function (array $arguments, Form $form) {
  77. $subtypeId = $arguments['subtype'];
  78. $this->chart = new ChartModel([
  79. 'subtype_id' => $subtypeId,
  80. ]);
  81. if ($subtypeId) {
  82. $companyId = auth()->user()->currentCompany->id;
  83. $generatedCode = AccountCode::generate($companyId, $subtypeId);
  84. $this->chart->code = $generatedCode;
  85. }
  86. $form->fill($this->chart->toArray())
  87. ->operation('create');
  88. });
  89. }
  90. private function getChartForm(bool $useActiveTab = true): array
  91. {
  92. return [
  93. Select::make('subtype_id')
  94. ->label('Type')
  95. ->required()
  96. ->live()
  97. ->disabled(static fn (string $operation, ?ChartModel $record) => $operation === 'edit' && $record?->default === true)
  98. ->options($this->getChartSubtypeOptions($useActiveTab))
  99. ->afterStateUpdated(static function (?string $state, Set $set): void {
  100. if ($state) {
  101. $companyId = auth()->user()->currentCompany->id;
  102. $generatedCode = AccountCode::generate($companyId, $state);
  103. $set('code', $generatedCode);
  104. }
  105. }),
  106. TextInput::make('code')
  107. ->label('Code')
  108. ->required()
  109. ->validationAttribute('account code')
  110. ->unique(table: ChartModel::class, column: 'code', ignoreRecord: true)
  111. ->validateAccountCode(static fn (Get $get) => $get('subtype_id')),
  112. TextInput::make('name')
  113. ->label('Name')
  114. ->required(),
  115. Select::make('currency_code')
  116. ->localizeLabel('Currency')
  117. ->relationship('currency', 'name')
  118. ->default(CurrencyAccessor::getDefaultCurrency())
  119. ->preload()
  120. ->searchable()
  121. ->visible(function (Get $get): bool {
  122. return filled($get('subtype_id')) && AccountSubtype::find($get('subtype_id'))->multi_currency;
  123. })
  124. ->live(),
  125. Textarea::make('description')
  126. ->label('Description')
  127. ->autosize(),
  128. ];
  129. }
  130. private function getChartSubtypeOptions($useActiveTab = true): array
  131. {
  132. $subtypes = $useActiveTab ?
  133. AccountSubtype::where('category', $this->activeTab)->get() :
  134. AccountSubtype::all();
  135. return $subtypes->groupBy(fn (AccountSubtype $subtype) => $subtype->type->getLabel())
  136. ->map(fn (Collection $subtypes, string $type) => $subtypes->mapWithKeys(static fn (AccountSubtype $subtype) => [$subtype->id => $subtype->name]))
  137. ->toArray();
  138. }
  139. protected function getHeaderActions(): array
  140. {
  141. return [
  142. CreateAction::make()
  143. ->button()
  144. ->label('Add New Account')
  145. ->model(ChartModel::class)
  146. ->form($this->getChartForm(false)),
  147. ];
  148. }
  149. public function getCategoryLabel($categoryValue): string
  150. {
  151. return AccountCategory::from($categoryValue)->getPluralLabel();
  152. }
  153. }