From 43d73f112bf4c065e571cfa321763f289fff691b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omer=20=C5=A0abi=C4=87?= Date: Tue, 29 Jul 2025 15:59:51 +0200 Subject: [PATCH 1/3] feat: add Currency model and migration --- ...5_07_29_133427_create_currencies_table.php | 23 +++++++++++++++++++ src/Models/Currency.php | 22 ++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 database/migrations/2025_07_29_133427_create_currencies_table.php create mode 100644 src/Models/Currency.php diff --git a/database/migrations/2025_07_29_133427_create_currencies_table.php b/database/migrations/2025_07_29_133427_create_currencies_table.php new file mode 100644 index 0000000..a095503 --- /dev/null +++ b/database/migrations/2025_07_29_133427_create_currencies_table.php @@ -0,0 +1,23 @@ +string('id', 3)->primary(); + $table->string('name'); + $table->string('is_active'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + public function down(): void + { + Schema::dropIfExists('world_currencies'); + } +}; diff --git a/src/Models/Currency.php b/src/Models/Currency.php new file mode 100644 index 0000000..13e01b3 --- /dev/null +++ b/src/Models/Currency.php @@ -0,0 +1,22 @@ + Date: Tue, 29 Jul 2025 14:00:24 +0000 Subject: [PATCH 2/3] style: fix code style --- .../migrations/2025_07_29_133427_create_currencies_table.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/database/migrations/2025_07_29_133427_create_currencies_table.php b/database/migrations/2025_07_29_133427_create_currencies_table.php index a095503..4241761 100644 --- a/database/migrations/2025_07_29_133427_create_currencies_table.php +++ b/database/migrations/2025_07_29_133427_create_currencies_table.php @@ -4,7 +4,8 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class extends Migration { +return new class extends Migration +{ public function up(): void { Schema::create('world_currencies', function (Blueprint $table) { From 701435688c48433394aa2f437522a063883ca9a0 Mon Sep 17 00:00:00 2001 From: Kilian Trunk Date: Mon, 4 Aug 2025 09:40:08 +0200 Subject: [PATCH 3/3] feat(currencies): implement currencies import and management (WO-5) --- database/factories/CurrencyFactory.php | 30 ++++ ...pdate_currencies_is_active_column_type.php | 22 +++ resources/lang/en/currencies.php | 75 ++++++++ resources/lang/hr/currencies.php | 75 ++++++++ resources/lang/sl/currencies.php | 75 ++++++++ resources/lang/sr/currencies.php | 75 ++++++++ .../World/Resources/CurrencyResource.php | 161 ++++++++++++++++++ .../CurrencyResource/Pages/ListCurrencies.php | 40 +++++ src/Jobs/ImportCurrencies.php | 95 +++++++++++ src/Models/Currency.php | 14 +- src/Policies/CurrencyPolicy.php | 84 +++++++++ tests/Feature/CurrencyResourceTest.php | 149 ++++++++++++++++ 12 files changed, 894 insertions(+), 1 deletion(-) create mode 100644 database/factories/CurrencyFactory.php create mode 100644 database/migrations/2025_07_30_105404_update_currencies_is_active_column_type.php create mode 100644 resources/lang/en/currencies.php create mode 100644 resources/lang/hr/currencies.php create mode 100644 resources/lang/sl/currencies.php create mode 100644 resources/lang/sr/currencies.php create mode 100644 src/Filament/Clusters/World/Resources/CurrencyResource.php create mode 100644 src/Filament/Clusters/World/Resources/CurrencyResource/Pages/ListCurrencies.php create mode 100644 src/Jobs/ImportCurrencies.php create mode 100644 src/Policies/CurrencyPolicy.php create mode 100644 tests/Feature/CurrencyResourceTest.php diff --git a/database/factories/CurrencyFactory.php b/database/factories/CurrencyFactory.php new file mode 100644 index 0000000..7a80417 --- /dev/null +++ b/database/factories/CurrencyFactory.php @@ -0,0 +1,30 @@ + + */ + public function definition(): array + { + return [ + 'id' => fake()->lexify('???'), + 'name' => fake()->currencyCode(), + 'is_active' => fake()->boolean(80), // 80% chance of being active + ]; + } +} diff --git a/database/migrations/2025_07_30_105404_update_currencies_is_active_column_type.php b/database/migrations/2025_07_30_105404_update_currencies_is_active_column_type.php new file mode 100644 index 0000000..e64a5a9 --- /dev/null +++ b/database/migrations/2025_07_30_105404_update_currencies_is_active_column_type.php @@ -0,0 +1,22 @@ +boolean('is_active')->default(false)->change(); + }); + } + + public function down(): void + { + Schema::table('world_currencies', function (Blueprint $table) { + $table->string('is_active')->change(); + }); + } +}; diff --git a/resources/lang/en/currencies.php b/resources/lang/en/currencies.php new file mode 100644 index 0000000..1b407a3 --- /dev/null +++ b/resources/lang/en/currencies.php @@ -0,0 +1,75 @@ + 'Currencies', + 'breadcrumb' => 'Currencies', + 'plural' => 'Currencies', + + 'table' => [ + 'id' => [ + 'label' => 'Code', + ], + 'name' => [ + 'label' => 'Name', + ], + 'is_active' => [ + 'label' => 'Active', + ], + ], + + 'actions' => [ + 'create' => [ + 'label' => 'New currency', + 'heading' => 'New Currency', + ], + 'edit' => [ + 'label' => 'Edit', + 'heading' => 'Edit Currency', + ], + 'delete' => [ + 'label' => 'Delete', + 'heading' => 'Delete Currency', + ], + 'restore' => [ + 'label' => 'Restore', + 'heading' => 'Restore Currency', + ], + 'force_delete' => [ + 'label' => 'Permanent delete', + 'heading' => 'Permanent Deletion of Currency', + 'description' => 'Are you sure you want to delete the currency :name? This action cannot be undone.', + ], + ], + + 'form' => [ + 'id' => [ + 'label' => 'Code', + 'helper' => 'Three-letter currency code (ISO 4217)', + ], + 'name' => [ + 'label' => 'Name', + ], + 'is_active' => [ + 'label' => 'Active', + ], + ], + + 'import' => [ + 'action_label' => 'Import Currencies', + 'modal_heading' => 'Import Currencies', + 'success_title' => 'Import Currencies', + 'success_message' => 'The import currencies job has been queued.', + ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Currencies Import Completed', + 'message' => 'All currencies have been successfully imported and updated.', + ], + 'failed' => [ + 'title' => 'Currencies Import Failed', + 'message' => 'Failed to import currencies data.', + ], + ], +]; diff --git a/resources/lang/hr/currencies.php b/resources/lang/hr/currencies.php new file mode 100644 index 0000000..29a2331 --- /dev/null +++ b/resources/lang/hr/currencies.php @@ -0,0 +1,75 @@ + 'Valute', + 'breadcrumb' => 'Valute', + 'plural' => 'Valute', + + 'table' => [ + 'id' => [ + 'label' => 'Kod', + ], + 'name' => [ + 'label' => 'Naziv', + ], + 'is_active' => [ + 'label' => 'Aktivna', + ], + ], + + 'actions' => [ + 'create' => [ + 'label' => 'Nova valuta', + 'heading' => 'Nova valuta', + ], + 'edit' => [ + 'label' => 'Uredi', + 'heading' => 'Uredi valutu', + ], + 'delete' => [ + 'label' => 'Obriši', + 'heading' => 'Obriši valutu', + ], + 'restore' => [ + 'label' => 'Vrati', + 'heading' => 'Vrati valutu', + ], + 'force_delete' => [ + 'label' => 'Trajno obriši', + 'heading' => 'Trajno brisanje valute', + 'description' => 'Jeste li sigurni da želite obrisati valutu :name? Ova radnja se ne može poništiti.', + ], + ], + + 'form' => [ + 'id' => [ + 'label' => 'Kod', + 'helper' => 'Troslovni kod valute (ISO 4217)', + ], + 'name' => [ + 'label' => 'Naziv', + ], + 'is_active' => [ + 'label' => 'Aktivna', + ], + ], + + 'import' => [ + 'action_label' => 'Uvezi valute', + 'modal_heading' => 'Uvezi valute', + 'success_title' => 'Uvezi valute', + 'success_message' => 'Posao uvoza valuta je dodan u red za izvršavanje.', + ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Uvoz valuta je završen', + 'message' => 'Sve valute su uspješno uvezene i ažurirane.', + ], + 'failed' => [ + 'title' => 'Uvoz valuta nije uspješan', + 'message' => 'Uvoz podataka o valutama nije uspješan.', + ], + ], +]; diff --git a/resources/lang/sl/currencies.php b/resources/lang/sl/currencies.php new file mode 100644 index 0000000..338247d --- /dev/null +++ b/resources/lang/sl/currencies.php @@ -0,0 +1,75 @@ + 'Valute', + 'breadcrumb' => 'Valute', + 'plural' => 'Valute', + + 'table' => [ + 'id' => [ + 'label' => 'Koda', + ], + 'name' => [ + 'label' => 'Ime', + ], + 'is_active' => [ + 'label' => 'Aktivna', + ], + ], + + 'actions' => [ + 'create' => [ + 'label' => 'Nova valuta', + 'heading' => 'Nova valuta', + ], + 'edit' => [ + 'label' => 'Uredi', + 'heading' => 'Uredi valuto', + ], + 'delete' => [ + 'label' => 'Izbriši', + 'heading' => 'Izbriši valuto', + ], + 'restore' => [ + 'label' => 'Obnovi', + 'heading' => 'Obnovi valuto', + ], + 'force_delete' => [ + 'label' => 'Trajno izbriši', + 'heading' => 'Trajno brisanje valute', + 'description' => 'Ali ste prepričani, da želite izbrisati valuto :name? Tega dejanja ni mogoče razveljaviti.', + ], + ], + + 'form' => [ + 'id' => [ + 'label' => 'Koda', + 'helper' => 'Tritrkovna koda valute (ISO 4217)', + ], + 'name' => [ + 'label' => 'Ime', + ], + 'is_active' => [ + 'label' => 'Aktivna', + ], + ], + + 'import' => [ + 'action_label' => 'Uvozi valute', + 'modal_heading' => 'Uvozi valute', + 'success_title' => 'Uvozi valute', + 'success_message' => 'Opravilo uvoza valut je bilo dodano v čakalno vrsto.', + ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Uvoz valut je končan', + 'message' => 'Vse valute so bile uspešno uvožene in posodobljene.', + ], + 'failed' => [ + 'title' => 'Uvoz valut ni uspel', + 'message' => 'Uvoz podatkov o valutah ni uspel.', + ], + ], +]; diff --git a/resources/lang/sr/currencies.php b/resources/lang/sr/currencies.php new file mode 100644 index 0000000..07ffa64 --- /dev/null +++ b/resources/lang/sr/currencies.php @@ -0,0 +1,75 @@ + 'Valute', + 'breadcrumb' => 'Valute', + 'plural' => 'Valute', + + 'table' => [ + 'id' => [ + 'label' => 'Kod', + ], + 'name' => [ + 'label' => 'Naziv', + ], + 'is_active' => [ + 'label' => 'Aktivna', + ], + ], + + 'actions' => [ + 'create' => [ + 'label' => 'Nova valuta', + 'heading' => 'Nova valuta', + ], + 'edit' => [ + 'label' => 'Uredi', + 'heading' => 'Uređivanje valute', + ], + 'delete' => [ + 'label' => 'Izbriši', + 'heading' => 'Brisanje valute', + ], + 'restore' => [ + 'label' => 'Obnovi', + 'heading' => 'Obnavljanje valute', + ], + 'force_delete' => [ + 'label' => 'Trajno izbriši', + 'heading' => 'Trajno brisanje valute', + 'description' => 'Da li ste sigurni da želite izbrisati valutu :name? Zapis više neće biti moguće obnoviti.', + ], + ], + + 'form' => [ + 'id' => [ + 'label' => 'Kod', + 'helper' => 'Troslovni kod valute (ISO 4217)', + ], + 'name' => [ + 'label' => 'Naziv', + ], + 'is_active' => [ + 'label' => 'Aktivna', + ], + ], + + 'import' => [ + 'action_label' => 'Uvezi valute', + 'modal_heading' => 'Uvoz valuta', + 'success_title' => 'Uvoz valuta', + 'success_message' => 'Zadatak za uvoz valuta je dodat u red čekanja.', + ], + + 'notifications' => [ + 'success' => [ + 'title' => 'Uvoz valuta završen', + 'message' => 'Sve valute su uspešno uvežene i ažurirane.', + ], + 'failed' => [ + 'title' => 'Uvoz valuta neuspešan', + 'message' => 'Neuspešan uvoz podataka valuta.', + ], + ], +]; diff --git a/src/Filament/Clusters/World/Resources/CurrencyResource.php b/src/Filament/Clusters/World/Resources/CurrencyResource.php new file mode 100644 index 0000000..1a4fa60 --- /dev/null +++ b/src/Filament/Clusters/World/Resources/CurrencyResource.php @@ -0,0 +1,161 @@ +schema([ + TextInput::make('id') + ->required() + ->length(3) + ->unique(table: Currency::class, ignoreRecord: true) + ->label(__('eclipse-world::currencies.form.id.label')) + ->helperText(__('eclipse-world::currencies.form.id.helper')), + + TextInput::make('name') + ->label(__('eclipse-world::currencies.form.name.label')) + ->required(), + + Toggle::make('is_active') + ->label(__('eclipse-world::currencies.form.is_active.label')) + ->default(true), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->defaultPaginationPageOption(50) + ->defaultSort('name') + ->striped() + ->columns([ + TextColumn::make('id') + ->label(__('eclipse-world::currencies.table.id.label')) + ->searchable() + ->sortable() + ->width(100), + + TextColumn::make('name') + ->label(__('eclipse-world::currencies.table.name.label')) + ->searchable() + ->sortable(), + + IconColumn::make('is_active') + ->label(__('eclipse-world::currencies.table.is_active.label')) + ->boolean() + ->width(100), + ]) + ->filters([ + TrashedFilter::make(), + ]) + ->actions([ + EditAction::make() + ->label(__('eclipse-world::currencies.actions.edit.label')) + ->modalHeading(__('eclipse-world::currencies.actions.edit.heading')), + ActionGroup::make([ + DeleteAction::make() + ->label(__('eclipse-world::currencies.actions.delete.label')) + ->modalHeading(__('eclipse-world::currencies.actions.delete.heading')), + RestoreAction::make() + ->label(__('eclipse-world::currencies.actions.restore.label')) + ->modalHeading(__('eclipse-world::currencies.actions.restore.heading')), + ForceDeleteAction::make() + ->label(__('eclipse-world::currencies.actions.force_delete.label')) + ->modalHeading(__('eclipse-world::currencies.actions.force_delete.heading')) + ->modalDescription(fn (Currency $record): string => __('eclipse-world::currencies.actions.force_delete.description', [ + 'name' => $record->name, + ])), + ]), + ]) + ->bulkActions([ + BulkActionGroup::make([ + DeleteBulkAction::make() + ->label(__('eclipse-world::currencies.actions.delete.label')), + RestoreBulkAction::make() + ->label(__('eclipse-world::currencies.actions.restore.label')), + ForceDeleteBulkAction::make() + ->label(__('eclipse-world::currencies.actions.force_delete.label')), + ]), + ]); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListCurrencies::route('/'), + ]; + } + + public static function getEloquentQuery(): Builder + { + return parent::getEloquentQuery() + ->withoutGlobalScopes([ + SoftDeletingScope::class, + ]); + } + + public static function getPermissionPrefixes(): array + { + return [ + 'view_any', + 'create', + 'update', + 'restore', + 'restore_any', + 'delete', + 'delete_any', + 'force_delete', + 'force_delete_any', + ]; + } + + public static function getNavigationLabel(): string + { + return __('eclipse-world::currencies.nav_label'); + } + + public static function getBreadcrumb(): string + { + return __('eclipse-world::currencies.breadcrumb'); + } + + public static function getPluralModelLabel(): string + { + return __('eclipse-world::currencies.plural'); + } +} diff --git a/src/Filament/Clusters/World/Resources/CurrencyResource/Pages/ListCurrencies.php b/src/Filament/Clusters/World/Resources/CurrencyResource/Pages/ListCurrencies.php new file mode 100644 index 0000000..be92da1 --- /dev/null +++ b/src/Filament/Clusters/World/Resources/CurrencyResource/Pages/ListCurrencies.php @@ -0,0 +1,40 @@ +label(__('eclipse-world::currencies.actions.create.label')) + ->modalHeading(__('eclipse-world::currencies.actions.create.heading')), + Action::make('import_currencies') + ->label(__('eclipse-world::currencies.import.action_label')) + ->icon('heroicon-o-arrow-down-tray') + ->action(function () { + // Dispatch the job + ImportCurrencies::dispatch(auth()->id(), App::getLocale()); + + // Show notification + Notification::make() + ->title(__('eclipse-world::currencies.import.success_title')) + ->body(__('eclipse-world::currencies.import.success_message')) + ->success() + ->send(); + }) + ->requiresConfirmation(), + ]; + } +} diff --git a/src/Jobs/ImportCurrencies.php b/src/Jobs/ImportCurrencies.php new file mode 100644 index 0000000..3f5c803 --- /dev/null +++ b/src/Jobs/ImportCurrencies.php @@ -0,0 +1,95 @@ +userId = $userId; + $this->locale = $locale; + } + + public function handle(): void + { + Log::info('Starting currencies import'); + + $user = $this->userId ? User::find($this->userId) : null; + + try { + // Load existing currencies into an associative array + $existingCurrencies = Currency::withTrashed()->get()->keyBy('id'); + + // Load new currency data from REST Countries API + $countries = json_decode(file_get_contents('https://raw.githubusercontent.com/mledoze/countries/master/dist/countries.json'), true); + + if (! $countries) { + throw new Exception('Failed to fetch or parse countries data'); + } + + $processedCurrencies = []; + + foreach ($countries as $rawData) { + if (! $rawData['independent'] || empty($rawData['currencies'])) { + continue; + } + + foreach ($rawData['currencies'] as $currencyCode => $currencyData) { + // Skip if we've already processed this currency + if (isset($processedCurrencies[$currencyCode])) { + continue; + } + + $data = [ + 'id' => $currencyCode, + 'name' => $currencyData['name'], + 'is_active' => true, + ]; + + if (isset($existingCurrencies[$currencyCode])) { + $existingCurrencies[$currencyCode]->update($data); + } else { + Currency::create($data); + } + + $processedCurrencies[$currencyCode] = true; + } + } + + Log::info('Currencies import completed'); + if ($user) { + $user->notify(new ImportFinishedNotification('success', 'currencies', null, $this->locale)); + } + } catch (Exception $e) { + Log::error('Currencies import failed: '.$e->getMessage()); + if ($user) { + $user->notify(new ImportFinishedNotification('failed', 'currencies', null, $this->locale)); + } + throw $e; + } + } +} diff --git a/src/Models/Currency.php b/src/Models/Currency.php index 13e01b3..16a2aee 100644 --- a/src/Models/Currency.php +++ b/src/Models/Currency.php @@ -2,12 +2,14 @@ namespace Eclipse\World\Models; +use Eclipse\World\Factories\CurrencyFactory; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Currency extends Model { - use SoftDeletes; + use HasFactory, SoftDeletes; protected $table = 'world_currencies'; @@ -16,7 +18,17 @@ class Currency extends Model public $incrementing = false; protected $fillable = [ + 'id', 'name', 'is_active', ]; + + protected $casts = [ + 'is_active' => 'boolean', + ]; + + protected static function newFactory(): CurrencyFactory + { + return CurrencyFactory::new(); + } } diff --git a/src/Policies/CurrencyPolicy.php b/src/Policies/CurrencyPolicy.php new file mode 100644 index 0000000..88a5ba8 --- /dev/null +++ b/src/Policies/CurrencyPolicy.php @@ -0,0 +1,84 @@ +can('view_any_currency'); + } + + /** + * Determine whether the user can create models. + */ + public function create(Authorizable $user): bool + { + return $user->can('create_currency'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(Authorizable $user, Currency $currency): bool + { + return $user->can('update_currency'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(Authorizable $user, Currency $currency): bool + { + return $user->can('delete_currency'); + } + + /** + * Determine whether the user can bulk delete. + */ + public function deleteAny(Authorizable $user): bool + { + return $user->can('delete_any_currency'); + } + + /** + * Determine whether the user can permanently delete. + */ + public function forceDelete(Authorizable $user, Currency $currency): bool + { + return $user->can('force_delete_currency'); + } + + /** + * Determine whether the user can permanently bulk delete. + */ + public function forceDeleteAny(Authorizable $user): bool + { + return $user->can('force_delete_any_currency'); + } + + /** + * Determine whether the user can restore. + */ + public function restore(Authorizable $user, Currency $currency): bool + { + return $user->can('restore_currency'); + } + + /** + * Determine whether the user can bulk restore. + */ + public function restoreAny(Authorizable $user): bool + { + return $user->can('restore_any_currency'); + } +} diff --git a/tests/Feature/CurrencyResourceTest.php b/tests/Feature/CurrencyResourceTest.php new file mode 100644 index 0000000..3656271 --- /dev/null +++ b/tests/Feature/CurrencyResourceTest.php @@ -0,0 +1,149 @@ +setUpSuperAdmin(); +}); + +test('unauthorized access can be prevented', function () { + // Create regular user with no permissions + $this->setUpCommonUser(); + + // Create test currency + $currency = Currency::factory()->create(); + + // View table + $this->get(CurrencyResource::getUrl()) + ->assertForbidden(); + + // Add direct permission to view the table, since otherwise any other action below is not available even for testing + $this->user->givePermissionTo('view_any_currency'); + + // Create currency + livewire(ListCurrencies::class) + ->assertActionDisabled('create'); + + // Edit currency + livewire(ListCurrencies::class) + ->assertCanSeeTableRecords([$currency]) + ->assertTableActionDisabled('edit', $currency); + + // Delete currency + livewire(ListCurrencies::class) + ->assertTableActionDisabled('delete', $currency) + ->assertTableBulkActionDisabled('delete'); + + // Restore and force delete + $currency->delete(); + $this->assertSoftDeleted($currency); + + livewire(ListCurrencies::class) + ->assertTableActionDisabled('restore', $currency) + ->assertTableBulkActionDisabled('restore') + ->assertTableActionDisabled('forceDelete', $currency) + ->assertTableBulkActionDisabled('forceDelete'); +}); + +test('currencies table can be displayed', function () { + $this->get(CurrencyResource::getUrl()) + ->assertSuccessful(); +}); + +test('form validation works', function () { + $component = livewire(ListCurrencies::class); + + // Test required fields + $component->callAction('create') + ->assertHasActionErrors([ + 'id' => 'required', + 'name' => 'required', + ]); + + // Test with valid data + $component->callAction('create', Currency::factory()->definition()) + ->assertHasNoActionErrors(); +}); + +test('new currency can be created', function () { + $data = Currency::factory()->definition(); + + livewire(ListCurrencies::class) + ->callAction('create', $data) + ->assertHasNoActionErrors(); + + $currency = Currency::where('id', $data['id'])->first(); + expect($currency)->toBeObject(); + + foreach ($data as $key => $val) { + expect($currency->$key)->toEqual($val); + } +}); + +test('existing currency can be updated', function () { + $currency = Currency::factory()->create([ + 'id' => 'USD', + 'name' => 'US Dollar', + 'is_active' => true, + ]); + + $data = \Illuminate\Support\Arr::except(Currency::factory()->definition(), ['id']); + + livewire(ListCurrencies::class) + ->callTableAction('edit', $currency, $data) + ->assertHasNoTableActionErrors(); + + $currency->refresh(); + + foreach ($data as $key => $val) { + expect($currency->$key)->toEqual($val); + } +}); + +test('currency can be deleted', function () { + $currency = Currency::factory()->create(); + + livewire(ListCurrencies::class) + ->callTableAction('delete', $currency) + ->assertHasNoTableActionErrors(); + + $this->assertSoftDeleted($currency); +}); + +test('currency can be restored', function () { + $currency = Currency::factory()->create(); + $currency->delete(); + + $this->assertSoftDeleted($currency); + + livewire(ListCurrencies::class) + ->filterTable('trashed') + ->assertTableActionExists('restore') + ->assertTableActionEnabled('restore', $currency) + ->assertTableActionVisible('restore', $currency) + ->callTableAction('restore', $currency) + ->assertHasNoTableActionErrors(); + + $this->assertNotSoftDeleted($currency); +}); + +test('currency can be force deleted', function () { + $currency = Currency::factory()->create(); + + $currency->delete(); + $this->assertSoftDeleted($currency); + + livewire(ListCurrencies::class) + ->filterTable('trashed') + ->assertTableActionExists('forceDelete') + ->assertTableActionEnabled('forceDelete', $currency) + ->assertTableActionVisible('forceDelete', $currency) + ->callTableAction('forceDelete', $currency) + ->assertHasNoTableActionErrors(); + + $this->assertModelMissing($currency); +});