Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

CurrencyResource.php 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <?php
  2. namespace App\Filament\Resources;
  3. use App\Filament\Resources\CurrencyResource\Pages;
  4. use App\Filament\Resources\CurrencyResource\RelationManagers;
  5. use App\Models\Banking\Account;
  6. use App\Models\Setting\Currency;
  7. use Closure;
  8. use Exception;
  9. use Filament\Forms;
  10. use Filament\Notifications\Notification;
  11. use Filament\Resources\Form;
  12. use Filament\Resources\Resource;
  13. use Filament\Resources\Table;
  14. use Filament\Tables;
  15. use Illuminate\Database\Eloquent\Builder;
  16. use Illuminate\Database\Eloquent\Model;
  17. use Illuminate\Database\Eloquent\SoftDeletingScope;
  18. use Illuminate\Support\Collection;
  19. use Illuminate\Support\Facades\Auth;
  20. use Illuminate\Support\Facades\Blade;
  21. use Illuminate\Support\HtmlString;
  22. use Wallo\FilamentSelectify\Components\ToggleButton;
  23. class CurrencyResource extends Resource
  24. {
  25. protected static ?string $model = Currency::class;
  26. protected static ?string $navigationIcon = 'heroicon-o-currency-dollar';
  27. protected static ?string $navigationGroup = 'Settings';
  28. public static function getEloquentQuery(): Builder
  29. {
  30. return parent::getEloquentQuery()->where('company_id', Auth::user()->currentCompany->id);
  31. }
  32. public static function form(Form $form): Form
  33. {
  34. return $form
  35. ->schema([
  36. Forms\Components\Section::make('General')
  37. ->description('The default currency is used for all transactions and reports and cannot be deleted. Currency precision determines the number of decimal places to display when formatting currency amounts. The currency rate is set to 1 for the default currency and is utilized as the basis for setting exchange rates for all other currencies.')
  38. ->schema([
  39. Forms\Components\Select::make('code')
  40. ->label('Code')
  41. ->options(Currency::getCurrencyCodes())
  42. ->searchable()
  43. ->placeholder('Select a currency code...')
  44. ->reactive()
  45. ->afterStateUpdated(static function (Closure $set, $state) {
  46. $code = $state;
  47. $name = config("money.{$code}.name");
  48. $precision = config("money.{$code}.precision");
  49. $symbol = config("money.{$code}.symbol");
  50. $symbol_first = config("money.{$code}.symbol_first");
  51. $decimal_mark = config("money.{$code}.decimal_mark");
  52. $thousands_separator = config("money.{$code}.thousands_separator");
  53. $set('name', $name);
  54. $set('precision', $precision);
  55. $set('symbol', $symbol);
  56. $set('symbol_first', $symbol_first);
  57. $set('decimal_mark', $decimal_mark);
  58. $set('thousands_separator', $thousands_separator);
  59. })
  60. ->required(),
  61. Forms\Components\TextInput::make('name')
  62. ->translateLabel()
  63. ->maxLength(100)
  64. ->required(),
  65. Forms\Components\TextInput::make('rate')
  66. ->label('Rate')
  67. ->dehydrateStateUsing(static fn (Closure $get, $state): bool => $get('enabled') === true ? '1' : $state) // rate is 1 when enabled is true
  68. ->numeric()
  69. ->reactive()
  70. ->disabled(static fn (Closure $get): bool => $get('enabled') === true) // disabled is true when enabled is true
  71. ->mask(static fn (Forms\Components\TextInput\Mask $mask) => $mask
  72. ->numeric()
  73. ->decimalPlaces(4)
  74. ->signed(false)
  75. ->padFractionalZeros(false)
  76. ->normalizeZeros(false)
  77. ->minValue(0.0001)
  78. ->maxValue(999999.9999)
  79. ->lazyPlaceholder(false))
  80. ->required(),
  81. Forms\Components\Select::make('precision')
  82. ->label('Precision')
  83. ->searchable()
  84. ->placeholder('Select the currency precision...')
  85. ->options(['0', '1', '2', '3', '4'])
  86. ->required(),
  87. Forms\Components\TextInput::make('symbol')
  88. ->label('Symbol')
  89. ->maxLength(5)
  90. ->required(),
  91. Forms\Components\Select::make('symbol_first')
  92. ->label('Symbol Position')
  93. ->searchable()
  94. ->boolean('Before Amount', 'After Amount', 'Select the currency symbol position...')
  95. ->required(),
  96. Forms\Components\TextInput::make('decimal_mark')
  97. ->label('Decimal Separator')
  98. ->maxLength(1)
  99. ->required(),
  100. Forms\Components\TextInput::make('thousands_separator')
  101. ->label('Thousands Separator')
  102. ->maxLength(1)
  103. ->required(),
  104. ToggleButton::make('enabled')
  105. ->label('Default Currency')
  106. ->reactive()
  107. ->offColor('danger')
  108. ->onColor('primary')
  109. ->afterStateUpdated(static fn (Closure $set, $state) => $state ? $set('rate', '1') : null),
  110. ])->columns(),
  111. ]);
  112. }
  113. /**
  114. * @throws Exception
  115. */
  116. public static function table(Table $table): Table
  117. {
  118. return $table
  119. ->columns([
  120. Tables\Columns\TextColumn::make('name')
  121. ->label('Name')
  122. ->weight('semibold')
  123. ->icon(static fn (Currency $record) => $record->enabled ? 'heroicon-o-lock-closed' : null)
  124. ->tooltip(static fn (Currency $record) => $record->enabled ? 'Default Currency' : null)
  125. ->iconPosition('after')
  126. ->searchable()
  127. ->sortable(),
  128. Tables\Columns\TextColumn::make('code')
  129. ->label('Code')
  130. ->searchable()
  131. ->sortable(),
  132. Tables\Columns\TextColumn::make('symbol')
  133. ->label('Symbol')
  134. ->searchable()
  135. ->sortable(),
  136. Tables\Columns\TextColumn::make('rate')
  137. ->label('Rate')
  138. ->formatStateUsing(static fn ($state) => str_contains($state, '.') ? rtrim(rtrim($state, '0'), '.') : null)
  139. ->searchable()
  140. ->sortable(),
  141. ])
  142. ->filters([
  143. //
  144. ])
  145. ->actions([
  146. Tables\Actions\EditAction::make(),
  147. Tables\Actions\DeleteAction::make()
  148. ->before(static function (Tables\Actions\DeleteAction $action, Currency $record) {
  149. $defaultCurrency = $record->enabled;
  150. $accountUsesCurrency = Account::where('currency_code', $record->code)->exists();
  151. if ($defaultCurrency) {
  152. Notification::make()
  153. ->danger()
  154. ->title('Action Denied')
  155. ->body(__('The :name currency is currently set as the default currency and cannot be deleted. Please set a different currency as your default before attempting to delete this one.', ['name' => $record->name]))
  156. ->persistent()
  157. ->send();
  158. $action->cancel();
  159. } elseif ($accountUsesCurrency) {
  160. Notification::make()
  161. ->danger()
  162. ->title('Action Denied')
  163. ->body(__('The :name currency is currently in use by one or more accounts and cannot be deleted. Please remove this currency from all accounts before attempting to delete it.', ['name' => $record->name]))
  164. ->persistent()
  165. ->send();
  166. $action->cancel();
  167. }
  168. }),
  169. ])
  170. ->bulkActions([
  171. Tables\Actions\DeleteBulkAction::make()
  172. ->before(static function (Tables\Actions\DeleteBulkAction $action, Collection $records) {
  173. foreach ($records as $record) {
  174. $defaultCurrency = $record->enabled;
  175. $accountUsesCurrency = Account::where('currency_code', $record->code)->exists();
  176. if ($defaultCurrency) {
  177. Notification::make()
  178. ->danger()
  179. ->title('Action Denied')
  180. ->body(__('The :name currency is currently set as the default currency and cannot be deleted. Please set a different currency as your default before attempting to delete this one.', ['name' => $record->name]))
  181. ->persistent()
  182. ->send();
  183. $action->cancel();
  184. } elseif ($accountUsesCurrency) {
  185. Notification::make()
  186. ->danger()
  187. ->title('Action Denied')
  188. ->body(__('The :name currency is currently in use by one or more accounts and cannot be deleted. Please remove this currency from all accounts before attempting to delete it.', ['name' => $record->name]))
  189. ->persistent()
  190. ->send();
  191. $action->cancel();
  192. }
  193. }
  194. }),
  195. ]);
  196. }
  197. public static function getRelations(): array
  198. {
  199. return [
  200. //
  201. ];
  202. }
  203. public static function getPages(): array
  204. {
  205. return [
  206. 'index' => Pages\ListCurrencies::route('/'),
  207. 'create' => Pages\CreateCurrency::route('/create'),
  208. 'edit' => Pages\EditCurrency::route('/{record}/edit'),
  209. ];
  210. }
  211. }