diff --git a/app/Http/Controllers/BulkCategoriesController.php b/app/Http/Controllers/BulkCategoriesController.php index 691ca14b9c..05b3189543 100644 --- a/app/Http/Controllers/BulkCategoriesController.php +++ b/app/Http/Controllers/BulkCategoriesController.php @@ -10,18 +10,37 @@ use App\Exceptions\ModelStillHasAssets; use App\Exceptions\ModelStillHasComponents; use App\Exceptions\ModelStillHasConsumables; use App\Exceptions\ModelStillHasLicenses; +use App\Models\Category; use Illuminate\Http\Request; class BulkCategoriesController extends Controller { - public function destroy($ids) + public function destroy(Request $request) { + // Authorize the user to delete categories + $this->authorize('delete', Category::class); + $errors = []; - foreach ($ids as $id) { + foreach ($request->ids as $id) { + $category = Category::find($id); + if (is_null($category)) { + $errors[] = 'Category not found'; + continue; + } try { - DestroyCategoryAction::run(category: $id); - } catch (ModelStillHasAccessories|ModelStillHasAssetModels|ModelStillHasAssets|ModelStillHasComponents|ModelStillHasConsumables|ModelStillHasLicenses $e) { - $errors[] = `{$id} still has {$id->thing}`; + DestroyCategoryAction::run(category: $category); + } catch (ModelStillHasAccessories $e) { + $errors[] = "{$category->name} still has associated items"; + } catch (ModelStillHasAssetModels) { + $errors[] = "{$category->name} still has asset models"; + } catch (ModelStillHasAssets) { + $errors[] = "{$category->name} still has assets"; + } catch (ModelStillHasComponents) { + $errors[] = "{$category->name} still has components"; + } catch (ModelStillHasConsumables) { + $errors[] = "{$category->name} still has consumables"; + } catch (ModelStillHasLicenses) { + $errors[] = "{$category->name} still has licenses"; } catch (\Exception $e) { report($e); $errors[] = 'Something went wrong'; @@ -30,7 +49,7 @@ class BulkCategoriesController extends Controller if (count($errors) > 0) { return redirect()->route('categories.index')->with('error', implode(', ', $errors)); } else { - return redirect()->route('categories.index')->with('success', trans('admin/suppliers/message.delete.success')); + return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success')); } } } diff --git a/app/Http/Controllers/BulkSuppliersController.php b/app/Http/Controllers/BulkSuppliersController.php index 1a9839df39..1962f79d17 100644 --- a/app/Http/Controllers/BulkSuppliersController.php +++ b/app/Http/Controllers/BulkSuppliersController.php @@ -6,22 +6,31 @@ use App\Actions\Suppliers\DestroySupplierAction; use App\Exceptions\ModelStillHasAssetMaintenances; use App\Exceptions\ModelStillHasAssets; use App\Exceptions\ModelStillHasLicenses; +use App\Models\Supplier; use Illuminate\Http\Request; class BulkSuppliersController extends Controller { - public function destroy($ids) + public function destroy(Request $request) { + // Authorize the user to delete suppliers + $this->authorize('delete', Supplier::class); + $errors = []; - foreach ($ids as $id) { + foreach ($request->ids as $id) { + $supplier = Supplier::find($id); + if (is_null($supplier)) { + $errors[] = 'Supplier not found'; + continue; + } try { - DestroySupplierAction::run(supplier: $id); + DestroySupplierAction::run(supplier: $supplier); } catch (ModelStillHasAssets $e) { - $errors[] = `{$id} still has assets`; + $errors[] = "{$supplier->name} still has assets"; } catch (ModelStillHasAssetMaintenances $e) { - $errors[] = `{$id} still has asset maintenances`; + $errors[] = "{$supplier->name} still has asset maintenances"; } catch (ModelStillHasLicenses $e) { - $errors[] = `{$id} still has licenses`; + $errors[] = "{$supplier->name} still has licenses"; } catch (\Exception $e) { report($e); $errors[] = 'Something went wrong'; diff --git a/app/Presenters/SupplierPresenter.php b/app/Presenters/SupplierPresenter.php index 20957cc648..b62b73a829 100644 --- a/app/Presenters/SupplierPresenter.php +++ b/app/Presenters/SupplierPresenter.php @@ -13,6 +13,11 @@ class SupplierPresenter extends Presenter public static function dataTableLayout() { $layout = [ + [ + 'field' => 'checkbox', + 'checkbox' => true, + 'titleTooltip' => trans('general.select_all_none'), + ], [ 'field' => 'id', 'searchable' => false, diff --git a/resources/views/components/tables/bulk-actions.blade.php b/resources/views/components/tables/bulk-actions.blade.php new file mode 100644 index 0000000000..09db7284fb --- /dev/null +++ b/resources/views/components/tables/bulk-actions.blade.php @@ -0,0 +1,30 @@ +@php + @endphp +
+
+ @csrf + + {{-- The sort and order will only be used if the cookie is actually empty (like on first-use) --}} + + + + + + +
+
diff --git a/resources/views/suppliers/index.blade.php b/resources/views/suppliers/index.blade.php index 918166ea6f..866f918749 100755 --- a/resources/views/suppliers/index.blade.php +++ b/resources/views/suppliers/index.blade.php @@ -18,9 +18,15 @@
-
+
- +
+ {{-- --}} + @include('partials.asset-bulk-actions', ['delete_only' => true]) + +
-
+
+
+
diff --git a/tests/Feature/Categories/Ui/BulkDeleteCategoriesTest.php b/tests/Feature/Categories/Ui/BulkDeleteCategoriesTest.php index c56d00afd5..1c04195fa1 100644 --- a/tests/Feature/Categories/Ui/BulkDeleteCategoriesTest.php +++ b/tests/Feature/Categories/Ui/BulkDeleteCategoriesTest.php @@ -2,6 +2,9 @@ namespace Tests\Feature\Categories\Ui; +use App\Models\AssetModel; +use App\Models\Category; +use App\Models\User; use Tests\Concerns\TestsPermissionsRequirement; use Tests\TestCase; @@ -9,17 +12,42 @@ class BulkDeleteCategoriesTest extends TestCase implements TestsPermissionsRequi { public function testRequiresPermission() { - // TODO: implement + $this->actingAs(User::factory()->create()) + ->delete(route('categories.bulk.delete'), [ + 'ids' => [1, 2, 3] + ]) + ->assertForbidden(); } public function test_category_cannot_be_bulk_deleted_if_models_still_associated() { - // TODO: implement + $category = Category::factory()->create(); + AssetModel::factory()->create(['category_id' => $category->id]); + + $this->actingAs(User::factory()->deleteCategories()->create()) + ->delete(route('categories.bulk.delete'), [ + 'ids' => [$category->id] + ]); + + $this->assertModelExists($category); + $this->assertNotSoftDeleted($category); } public function test_category_can_be_bulk_deleted_if_no_models_associated() { - // TODO: implement + $category1 = Category::factory()->create(); + $category2 = Category::factory()->create(); + $category3 = Category::factory()->create(); + + $this->actingAs(User::factory()->deleteCategories()->create()) + ->delete(route('categories.bulk.delete'), [ + 'ids' => [$category1->id, $category2->id, $category3->id] + ]) + ->assertRedirect(route('categories.index')); + + $this->assertSoftDeleted($category1); + $this->assertSoftDeleted($category2); + $this->assertSoftDeleted($category3); } diff --git a/tests/Feature/Suppliers/Api/DeleteSuppliersTest.php b/tests/Feature/Suppliers/Api/DeleteSuppliersTest.php deleted file mode 100644 index 06b85b75aa..0000000000 --- a/tests/Feature/Suppliers/Api/DeleteSuppliersTest.php +++ /dev/null @@ -1,53 +0,0 @@ -create(); - - $this->actingAsForApi(User::factory()->create()) - ->deleteJson(route('api.suppliers.destroy', $supplier)) - ->assertForbidden(); - - $this->assertNotSoftDeleted($supplier); - } - - public function testCannotDeleteSupplierWithDataStillAssociated() - { - $supplierWithAsset = Supplier::factory()->hasAssets()->create(); - $supplierWithAssetMaintenance = Supplier::factory()->has(AssetMaintenance::factory(), 'asset_maintenances')->create(); - $supplierWithLicense = Supplier::factory()->hasLicenses()->create(); - - $actor = $this->actingAsForApi(User::factory()->deleteSuppliers()->create()); - - $actor->deleteJson(route('api.suppliers.destroy', $supplierWithAsset))->assertStatusMessageIs('error'); - $actor->deleteJson(route('api.suppliers.destroy', $supplierWithAssetMaintenance))->assertStatusMessageIs('error'); - $actor->deleteJson(route('api.suppliers.destroy', $supplierWithLicense))->assertStatusMessageIs('error'); - - - $this->assertNotSoftDeleted($supplierWithAsset); - $this->assertNotSoftDeleted($supplierWithAssetMaintenance); - $this->assertNotSoftDeleted($supplierWithLicense); - } - - public function testCanDeleteSupplier() - { - $supplier = Supplier::factory()->create(); - - $this->actingAsForApi(User::factory()->deleteSuppliers()->create()) - ->deleteJson(route('api.suppliers.destroy', $supplier)) - ->assertOk() - ->assertStatusMessageIs('success'); - - $this->assertSoftDeleted($supplier); - } -} diff --git a/tests/Feature/Suppliers/Ui/BulkDeleteSuppliersTest.php b/tests/Feature/Suppliers/Ui/BulkDeleteSuppliersTest.php index 5ee939ad85..d80091eeed 100644 --- a/tests/Feature/Suppliers/Ui/BulkDeleteSuppliersTest.php +++ b/tests/Feature/Suppliers/Ui/BulkDeleteSuppliersTest.php @@ -2,6 +2,9 @@ namespace Tests\Feature\Suppliers\Ui; +use App\Models\Asset; +use App\Models\Supplier; +use App\Models\User; use Tests\Concerns\TestsPermissionsRequirement; use Tests\TestCase; @@ -9,16 +12,41 @@ class BulkDeleteSuppliersTest extends TestCase implements TestsPermissionsRequir { public function testRequiresPermission() { - // TODO: implement + $this->actingAs(User::factory()->create()) + ->delete(route('suppliers.bulk.delete'), [ + 'ids' => [1, 2, 3] + ]) + ->assertForbidden(); } public function test_suppliers_cannot_be_bulk_deleted_if_models_still_associated() { - // TODO: implement + $supplier = Supplier::factory()->create(); + Asset::factory()->create(['supplier_id' => $supplier->id]); + + $this->actingAs(User::factory()->deleteSuppliers()->create()) + ->delete(route('suppliers.bulk.delete'), [ + 'ids' => [$supplier->id] + ]); + + $this->assertModelExists($supplier); + $this->assertNotSoftDeleted($supplier); } public function test_supplier_can_be_bulk_deleted() { - // TODO: implement + $supplier1 = Supplier::factory()->create(); + $supplier2 = Supplier::factory()->create(); + $supplier3 = Supplier::factory()->create(); + + $this->actingAs(User::factory()->deleteSuppliers()->create()) + ->delete(route('suppliers.bulk.delete'), [ + 'ids' => [$supplier1->id, $supplier2->id, $supplier3->id] + ]) + ->assertRedirect(route('suppliers.index')); + + $this->assertSoftDeleted($supplier1); + $this->assertSoftDeleted($supplier2); + $this->assertSoftDeleted($supplier3); } } \ No newline at end of file