diff --git a/app/Http/Controllers/Api/AccessoriesController.php b/app/Http/Controllers/Api/AccessoriesController.php index 19951b6589..d1ef72bcca 100644 --- a/app/Http/Controllers/Api/AccessoriesController.php +++ b/app/Http/Controllers/Api/AccessoriesController.php @@ -137,7 +137,6 @@ class AccessoriesController extends Controller */ public function store(StoreAccessoryRequest $request) { - $this->authorize('create', Accessory::class); $accessory = new Accessory; $accessory->fill($request->all()); $accessory = $request->handleImages($accessory); @@ -197,9 +196,6 @@ class AccessoriesController extends Controller $this->authorize('view', Accessory::class); $accessory = Accessory::with('lastCheckout')->findOrFail($id); - if (! Company::isCurrentUserHasAccess($accessory)) { - return ['total' => 0, 'rows' => []]; - } $offset = request('offset', 0); $limit = request('limit', 50); @@ -325,7 +321,7 @@ class AccessoriesController extends Controller $accessory = Accessory::find($accessory_checkout->accessory_id); $this->authorize('checkin', $accessory); - $logaction = $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note')); + $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note')); // Was the accessory updated? if ($accessory_checkout->delete()) { @@ -333,14 +329,6 @@ class AccessoriesController extends Controller $user = User::find($accessory_checkout->assigned_to); } - $data['log_id'] = $logaction->id; - $data['first_name'] = $user->first_name; - $data['last_name'] = $user->last_name; - $data['item_name'] = $accessory->name; - $data['checkin_date'] = $logaction->created_at; - $data['item_tag'] = ''; - $data['note'] = $logaction->note; - return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkin.success'))); } diff --git a/app/Models/Loggable.php b/app/Models/Loggable.php index 249afc00a8..72a7a7f262 100644 --- a/app/Models/Loggable.php +++ b/app/Models/Loggable.php @@ -117,7 +117,6 @@ trait Loggable */ public function logCheckin($target, $note, $action_date = null, $originalValues = []) { - $settings = Setting::getSettings(); $log = new Actionlog; if($target != null){ @@ -171,39 +170,6 @@ trait Loggable $log->logaction('checkin from'); -// $params = [ -// 'target' => $target, -// 'item' => $log->item, -// 'admin' => $log->user, -// 'note' => $note, -// 'target_type' => $log->target_type, -// 'settings' => $settings, -// ]; -// -// -// $checkinClass = null; -// -// if (method_exists($target, 'notify')) { -// try { -// $target->notify(new static::$checkinClass($params)); -// } catch (\Exception $e) { -// Log::debug($e); -// } -// -// } -// -// // Send to the admin, if settings dictate -// $recipient = new \App\Models\Recipients\AdminRecipient(); -// -// if (($settings->admin_cc_email!='') && (static::$checkinClass!='')) { -// try { -// $recipient->notify(new static::$checkinClass($params)); -// } catch (\Exception $e) { -// Log::debug($e); -// } -// -// } - return $log; } diff --git a/database/factories/AccessoryFactory.php b/database/factories/AccessoryFactory.php index ea68e2b57f..6442472d5f 100644 --- a/database/factories/AccessoryFactory.php +++ b/database/factories/AccessoryFactory.php @@ -3,7 +3,6 @@ namespace Database\Factories; use App\Models\Accessory; -use App\Models\AccessoryCheckout; use App\Models\Category; use App\Models\Location; use App\Models\Manufacturer; @@ -156,4 +155,19 @@ class AccessoryFactory extends Factory ]); }); } + + public function checkedOutToUsers(array $users) + { + return $this->afterCreating(function (Accessory $accessory) use ($users) { + foreach ($users as $user) { + $accessory->checkouts()->create([ + 'accessory_id' => $accessory->id, + 'created_at' => Carbon::now(), + 'user_id' => 1, + 'assigned_to' => $user->id, + 'assigned_type' => User::class, + ]); + } + }); + } } diff --git a/tests/Feature/Accessories/Api/AccessoriesForSelectListTest.php b/tests/Feature/Accessories/Api/AccessoriesForSelectListTest.php new file mode 100644 index 0000000000..f2c2185edc --- /dev/null +++ b/tests/Feature/Accessories/Api/AccessoriesForSelectListTest.php @@ -0,0 +1,59 @@ +count(2)->create(); + + $accessoryA = Accessory::factory()->for($companyA)->create(); + $accessoryB = Accessory::factory()->for($companyB)->create(); + + $superuser = User::factory()->superuser()->create(); + $userInCompanyA = $companyA->users()->save(User::factory()->viewAccessories()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewAccessories()->make()); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.accessories.selectlist')) + ->assertOk() + ->assertJsonPath('total_count', 1) + ->assertResponseContainsInResults($accessoryA) + ->assertResponseDoesNotContainInResults($accessoryB); + + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.accessories.selectlist')) + ->assertOk() + ->assertJsonPath('total_count', 1) + ->assertResponseDoesNotContainInResults($accessoryA) + ->assertResponseContainsInResults($accessoryB); + + $this->actingAsForApi($superuser) + ->getJson(route('api.accessories.selectlist')) + ->assertOk() + ->assertJsonPath('total_count', 2) + ->assertResponseContainsInResults($accessoryA) + ->assertResponseContainsInResults($accessoryB); + } + + public function testCanGetAccessoriesForSelectList() + { + [$accessoryA, $accessoryB] = Accessory::factory()->count(2)->create(); + + $this->actingAsForApi(User::factory()->viewAccessories()->create()) + ->getJson(route('api.accessories.selectlist')) + ->assertOk() + ->assertJsonPath('total_count', 2) + ->assertResponseContainsInResults($accessoryA) + ->assertResponseContainsInResults($accessoryB); + } +} diff --git a/tests/Feature/Accessories/Api/IndexAccessoryCheckoutsTest.php b/tests/Feature/Accessories/Api/IndexAccessoryCheckoutsTest.php new file mode 100644 index 0000000000..38f1e99e5d --- /dev/null +++ b/tests/Feature/Accessories/Api/IndexAccessoryCheckoutsTest.php @@ -0,0 +1,84 @@ +create(); + + $this->actingAsForApi(User::factory()->create()) + ->getJson(route('api.accessories.checkedout', $accessory)) + ->assertForbidden(); + } + + public function testAdheresToFullMultipleCompaniesSupportScoping() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $accessoryA = Accessory::factory()->for($companyA)->create(); + $accessoryB = Accessory::factory()->for($companyB)->create(); + + $superuser = User::factory()->superuser()->create(); + $userInCompanyA = $companyA->users()->save(User::factory()->viewAccessories()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewAccessories()->make()); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.accessories.checkedout', $accessoryB)) + ->assertStatusMessageIs('error'); + + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.accessories.checkedout', $accessoryA)) + ->assertStatusMessageIs('error'); + + $this->actingAsForApi($superuser) + ->getJson(route('api.accessories.checkedout', $accessoryA)) + ->assertOk(); + } + + public function testCanGetAccessoryCheckouts() + { + [$userA, $userB] = User::factory()->count(2)->create(); + + $accessory = Accessory::factory()->checkedOutToUsers([$userA, $userB])->create(); + + $this->assertEquals(2, $accessory->checkouts()->count()); + + $this->actingAsForApi(User::factory()->viewAccessories()->create()) + ->getJson(route('api.accessories.checkedout', $accessory)) + ->assertOk() + ->assertJsonPath('total', 2) + ->assertJsonPath('rows.0.assigned_to.id', $userA->id) + ->assertJsonPath('rows.1.assigned_to.id', $userB->id); + } + + public function testCanGetAccessoryCheckoutsWithOffsetAndLimitInQueryString() + { + [$userA, $userB, $userC] = User::factory()->count(3)->create(); + + $accessory = Accessory::factory()->checkedOutToUsers([$userA, $userB, $userC])->create(); + + $actor = $this->actingAsForApi(User::factory()->viewAccessories()->create()); + + $actor->getJson(route('api.accessories.checkedout', ['accessory' => $accessory->id, 'limit' => 1])) + ->assertOk() + ->assertJsonPath('total', 3) + ->assertJsonPath('rows.0.assigned_to.id', $userA->id); + + $actor->getJson(route('api.accessories.checkedout', ['accessory' => $accessory->id, 'limit' => 2, 'offset' => 1])) + ->assertOk() + ->assertJsonPath('total', 3) + ->assertJsonPath('rows.0.assigned_to.id', $userB->id) + ->assertJsonPath('rows.1.assigned_to.id', $userC->id); + } +} diff --git a/tests/Feature/Accessories/Api/IndexAccessoryTest.php b/tests/Feature/Accessories/Api/IndexAccessoryTest.php index 509e6fd452..96263f5380 100644 --- a/tests/Feature/Accessories/Api/IndexAccessoryTest.php +++ b/tests/Feature/Accessories/Api/IndexAccessoryTest.php @@ -2,15 +2,69 @@ namespace Tests\Feature\Accessories\Api; +use App\Models\Accessory; +use App\Models\Company; use App\Models\User; +use Tests\Concerns\TestsFullMultipleCompaniesSupport; +use Tests\Concerns\TestsPermissionsRequirement; use Tests\TestCase; -class IndexAccessoryTest extends TestCase +class IndexAccessoryTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement { - public function testPermissionRequiredToViewAccessoriesIndex() + public function testRequiresPermission() { $this->actingAsForApi(User::factory()->create()) ->getJson(route('api.accessories.index')) ->assertForbidden(); } + + public function testAdheresToFullMultipleCompaniesSupportScoping() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $accessoryA = Accessory::factory()->for($companyA)->create(['name' => 'Accessory A']); + $accessoryB = Accessory::factory()->for($companyB)->create(['name' => 'Accessory B']); + $accessoryC = Accessory::factory()->for($companyB)->create(['name' => 'Accessory C']); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewAccessories()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewAccessories()->make()); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.accessories.index')) + ->assertOk() + ->assertResponseContainsInRows($accessoryA) + ->assertResponseDoesNotContainInRows($accessoryB) + ->assertResponseDoesNotContainInRows($accessoryC); + + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.accessories.index')) + ->assertOk() + ->assertResponseDoesNotContainInRows($accessoryA) + ->assertResponseContainsInRows($accessoryB) + ->assertResponseContainsInRows($accessoryC); + + $this->actingAsForApi($superUser) + ->getJson(route('api.accessories.index')) + ->assertOk() + ->assertResponseContainsInRows($accessoryA) + ->assertResponseContainsInRows($accessoryB) + ->assertResponseContainsInRows($accessoryC); + } + + public function testCanGetAccessories() + { + $user = User::factory()->viewAccessories()->create(); + + $accessoryA = Accessory::factory()->create(['name' => 'Accessory A']); + $accessoryB = Accessory::factory()->create(['name' => 'Accessory B']); + + $this->actingAsForApi($user) + ->getJson(route('api.accessories.index')) + ->assertOk() + ->assertResponseContainsInRows($accessoryA) + ->assertResponseContainsInRows($accessoryB); + } } diff --git a/tests/Feature/Accessories/Api/ShowAccessoryTest.php b/tests/Feature/Accessories/Api/ShowAccessoryTest.php index 2bc3e88bfc..117d725007 100644 --- a/tests/Feature/Accessories/Api/ShowAccessoryTest.php +++ b/tests/Feature/Accessories/Api/ShowAccessoryTest.php @@ -3,12 +3,15 @@ namespace Tests\Feature\Accessories\Api; use App\Models\Accessory; +use App\Models\Company; use App\Models\User; +use Tests\Concerns\TestsFullMultipleCompaniesSupport; +use Tests\Concerns\TestsPermissionsRequirement; use Tests\TestCase; -class ShowAccessoryTest extends TestCase +class ShowAccessoryTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement { - public function testPermissionRequiredToShowAccessory() + public function testRequiresPermission() { $accessory = Accessory::factory()->create(); @@ -16,4 +19,43 @@ class ShowAccessoryTest extends TestCase ->getJson(route('api.accessories.show', $accessory)) ->assertForbidden(); } + + public function testAdheresToFullMultipleCompaniesSupportScoping() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $accessoryForCompanyA = Accessory::factory()->for($companyA)->create(); + + $superuser = User::factory()->superuser()->create(); + $userForCompanyB = User::factory()->for($companyB)->viewAccessories()->create(); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAsForApi($userForCompanyB) + ->getJson(route('api.accessories.show', $accessoryForCompanyA)) + ->assertOk() + ->assertStatusMessageIs('error'); + + $this->actingAsForApi($superuser) + ->getJson(route('api.accessories.show', $accessoryForCompanyA)) + ->assertOk() + ->assertJsonFragment([ + 'id' => $accessoryForCompanyA->id, + ]); + } + + public function testCanGetSingleAccessory() + { + $accessory = Accessory::factory()->checkedOutToUser()->create(['name' => 'My Accessory']); + + $this->actingAsForApi(User::factory()->viewAccessories()->create()) + ->getJson(route('api.accessories.show', $accessory)) + ->assertOk() + ->assertJsonFragment([ + 'id' => $accessory->id, + 'name' => 'My Accessory', + 'checkouts_count' => 1, + ]); + + } } diff --git a/tests/Feature/Accessories/Api/StoreAccessoryTest.php b/tests/Feature/Accessories/Api/StoreAccessoryTest.php index d29ff32f6e..22ba715519 100644 --- a/tests/Feature/Accessories/Api/StoreAccessoryTest.php +++ b/tests/Feature/Accessories/Api/StoreAccessoryTest.php @@ -2,15 +2,97 @@ namespace Tests\Feature\Accessories\Api; +use App\Models\Category; +use App\Models\Company; +use App\Models\Location; +use App\Models\Manufacturer; +use App\Models\Supplier; use App\Models\User; +use Tests\Concerns\TestsFullMultipleCompaniesSupport; +use Tests\Concerns\TestsPermissionsRequirement; use Tests\TestCase; -class StoreAccessoryTest extends TestCase +class StoreAccessoryTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement { - public function testPermissionRequiredToStoreAccessory() + public function testRequiresPermission() { $this->actingAsForApi(User::factory()->create()) ->postJson(route('api.accessories.store')) ->assertForbidden(); } + + public function testAdheresToFullMultipleCompaniesSupportScoping() + { + $this->markTestSkipped('This behavior is not implemented'); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + $userInCompanyA = User::factory()->for($companyA)->createAccessories()->create(); + + $this->settings->enableMultipleFullCompanySupport(); + + // attempt to store an accessory for company B + $this->actingAsForApi($userInCompanyA) + ->postJson(route('api.accessories.store'), [ + 'category_id' => Category::factory()->forAccessories()->create()->id, + 'name' => 'My Awesome Accessory', + 'qty' => 1, + 'company_id' => $companyB->id, + ])->assertStatusMessageIs('error'); + + $this->assertDatabaseMissing('accessories', [ + 'name' => 'My Awesome Accessory', + ]); + } + + public function testValidation() + { + $this->actingAsForApi(User::factory()->createAccessories()->create()) + ->postJson(route('api.accessories.store'), [ + // + ]) + ->assertStatusMessageIs('error') + ->assertMessagesContains([ + 'category_id', + 'name', + 'qty', + ]); + } + + public function testCanStoreAccessory() + { + $category = Category::factory()->forAccessories()->create(); + $company = Company::factory()->create(); + $location = Location::factory()->create(); + $manufacturer = Manufacturer::factory()->create(); + $supplier = Supplier::factory()->create(); + + $this->actingAsForApi(User::factory()->createAccessories()->create()) + ->postJson(route('api.accessories.store'), [ + 'name' => 'My Awesome Accessory', + 'qty' => 2, + 'order_number' => '12345', + 'purchase_cost' => 100.00, + 'purchase_date' => '2024-09-18', + 'model_number' => '98765', + 'category_id' => $category->id, + 'company_id' => $company->id, + 'location_id' => $location->id, + 'manufacturer_id' => $manufacturer->id, + 'supplier_id' => $supplier->id, + ])->assertStatusMessageIs('success'); + + $this->assertDatabaseHas('accessories', [ + 'name' => 'My Awesome Accessory', + 'qty' => 2, + 'order_number' => '12345', + 'purchase_cost' => 100.00, + 'purchase_date' => '2024-09-18', + 'model_number' => '98765', + 'category_id' => $category->id, + 'company_id' => $company->id, + 'location_id' => $location->id, + 'manufacturer_id' => $manufacturer->id, + 'supplier_id' => $supplier->id, + ]); + } } diff --git a/tests/Feature/Accessories/Api/UpdateAccessoryTest.php b/tests/Feature/Accessories/Api/UpdateAccessoryTest.php index 45923651f2..a0009a732a 100644 --- a/tests/Feature/Accessories/Api/UpdateAccessoryTest.php +++ b/tests/Feature/Accessories/Api/UpdateAccessoryTest.php @@ -3,12 +3,19 @@ namespace Tests\Feature\Accessories\Api; use App\Models\Accessory; +use App\Models\Category; +use App\Models\Company; +use App\Models\Location; +use App\Models\Manufacturer; +use App\Models\Supplier; use App\Models\User; +use Tests\Concerns\TestsFullMultipleCompaniesSupport; +use Tests\Concerns\TestsPermissionsRequirement; use Tests\TestCase; -class UpdateAccessoryTest extends TestCase +class UpdateAccessoryTest extends TestCase implements TestsFullMultipleCompaniesSupport, TestsPermissionsRequirement { - public function testPermissionRequiredToUpdateAccessory() + public function testRequiresPermission() { $accessory = Accessory::factory()->create(); @@ -16,4 +23,84 @@ class UpdateAccessoryTest extends TestCase ->patchJson(route('api.accessories.update', $accessory)) ->assertForbidden(); } + + public function testAdheresToFullMultipleCompaniesSupportScoping() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $accessoryA = Accessory::factory()->for($companyA)->create(['name' => 'A Name to Change']); + $accessoryB = Accessory::factory()->for($companyB)->create(['name' => 'A Name to Change']); + $accessoryC = Accessory::factory()->for($companyB)->create(['name' => 'A Name to Change']); + + $superuser = User::factory()->superuser()->create(); + $userInCompanyA = $companyA->users()->save(User::factory()->editAccessories()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->editAccessories()->make()); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAsForApi($userInCompanyA) + ->patchJson(route('api.accessories.update', $accessoryB), ['name' => 'New Name']) + ->assertStatusMessageIs('error'); + + $this->actingAsForApi($userInCompanyB) + ->patchJson(route('api.accessories.update', $accessoryA), ['name' => 'New Name']) + ->assertStatusMessageIs('error'); + + $this->actingAsForApi($superuser) + ->patchJson(route('api.accessories.update', $accessoryC), ['name' => 'New Name']) + ->assertOk(); + + $this->assertEquals('A Name to Change', $accessoryA->fresh()->name); + $this->assertEquals('A Name to Change', $accessoryB->fresh()->name); + $this->assertEquals('New Name', $accessoryC->fresh()->name); + } + + public function testCanUpdateAccessoryViaPatch() + { + [$categoryA, $categoryB] = Category::factory()->count(2)->create(); + [$companyA, $companyB] = Company::factory()->count(2)->create(); + [$locationA, $locationB] = Location::factory()->count(2)->create(); + [$manufacturerA, $manufacturerB] = Manufacturer::factory()->count(2)->create(); + [$supplierA, $supplierB] = Supplier::factory()->count(2)->create(); + + $accessory = Accessory::factory()->create([ + 'name' => 'A Name to Change', + 'qty' => 5, + 'order_number' => 'A12345', + 'purchase_cost' => 99.99, + 'model_number' => 'ABC098', + 'category_id' => $categoryA->id, + 'company_id' => $companyA->id, + 'location_id' => $locationA->id, + 'manufacturer_id' => $manufacturerA->id, + 'supplier_id' => $supplierA->id, + ]); + + $this->actingAsForApi(User::factory()->editAccessories()->create()) + ->patchJson(route('api.accessories.update', $accessory), [ + 'name' => 'A New Name', + 'qty' => 10, + 'order_number' => 'B54321', + 'purchase_cost' => 199.99, + 'model_number' => 'XYZ123', + 'category_id' => $categoryB->id, + 'company_id' => $companyB->id, + 'location_id' => $locationB->id, + 'manufacturer_id' => $manufacturerB->id, + 'supplier_id' => $supplierB->id, + ]) + ->assertOk(); + + $accessory = $accessory->fresh(); + $this->assertEquals('A New Name', $accessory->name); + $this->assertEquals(10, $accessory->qty); + $this->assertEquals('B54321', $accessory->order_number); + $this->assertEquals(199.99, $accessory->purchase_cost); + $this->assertEquals('XYZ123', $accessory->model_number); + $this->assertEquals($categoryB->id, $accessory->category_id); + $this->assertEquals($companyB->id, $accessory->company_id); + $this->assertEquals($locationB->id, $accessory->location_id); + $this->assertEquals($manufacturerB->id, $accessory->manufacturer_id); + $this->assertEquals($supplierB->id, $accessory->supplier_id); + } } diff --git a/tests/Feature/Checkins/Api/AccessoryCheckinTest.php b/tests/Feature/Checkins/Api/AccessoryCheckinTest.php new file mode 100644 index 0000000000..d5f45f22ae --- /dev/null +++ b/tests/Feature/Checkins/Api/AccessoryCheckinTest.php @@ -0,0 +1,86 @@ +checkedOutToUser()->create(); + $accessoryCheckout = $accessory->checkouts->first(); + + $this->actingAsForApi(User::factory()->create()) + ->postJson(route('api.accessories.checkin', $accessoryCheckout)) + ->assertForbidden(); + } + + public function testAdheresToFullMultipleCompaniesSupportScoping() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = User::factory()->for($companyA)->checkinAccessories()->create(); + $accessoryForCompanyB = Accessory::factory()->for($companyB)->checkedOutToUser()->create(); + $anotherAccessoryForCompanyB = Accessory::factory()->for($companyB)->checkedOutToUser()->create(); + + $this->assertEquals(1, $accessoryForCompanyB->checkouts->count()); + $this->assertEquals(1, $anotherAccessoryForCompanyB->checkouts->count()); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAsForApi($userInCompanyA) + ->postJson(route('api.accessories.checkin', $accessoryForCompanyB->checkouts->first())) + ->assertForbidden(); + + $this->actingAsForApi($superUser) + ->postJson(route('api.accessories.checkin', $anotherAccessoryForCompanyB->checkouts->first())) + ->assertStatusMessageIs('success'); + + $this->assertEquals(1, $accessoryForCompanyB->fresh()->checkouts->count(), 'Accessory should not be checked in'); + $this->assertEquals(0, $anotherAccessoryForCompanyB->fresh()->checkouts->count(), 'Accessory should be checked in'); + } + + public function testCanCheckinAccessory() + { + $accessory = Accessory::factory()->checkedOutToUser()->create(); + + $this->assertEquals(1, $accessory->checkouts->count()); + + $accessoryCheckout = $accessory->checkouts->first(); + + $this->actingAsForApi(User::factory()->checkinAccessories()->create()) + ->postJson(route('api.accessories.checkin', $accessoryCheckout)) + ->assertStatusMessageIs('success'); + + $this->assertEquals(0, $accessory->fresh()->checkouts->count(), 'Accessory should be checked in'); + } + + public function testCheckinIsLogged() + { + $user = User::factory()->create(); + $actor = User::factory()->checkinAccessories()->create(); + + $accessory = Accessory::factory()->checkedOutToUser($user)->create(); + $accessoryCheckout = $accessory->checkouts->first(); + + $this->actingAsForApi($actor) + ->postJson(route('api.accessories.checkin', $accessoryCheckout)) + ->assertStatusMessageIs('success'); + + $this->assertDatabaseHas('action_logs', [ + 'created_by' => $actor->id, + 'action_type' => 'checkin from', + 'target_id' => $user->id, + 'target_type' => User::class, + 'item_id' => $accessory->id, + 'item_type' => Accessory::class, + ]); + } +} diff --git a/tests/Feature/Checkouts/Api/AccessoryCheckoutTest.php b/tests/Feature/Checkouts/Api/AccessoryCheckoutTest.php index c914020d5a..765b8436a0 100644 --- a/tests/Feature/Checkouts/Api/AccessoryCheckoutTest.php +++ b/tests/Feature/Checkouts/Api/AccessoryCheckoutTest.php @@ -7,11 +7,12 @@ use App\Models\Actionlog; use App\Models\User; use App\Notifications\CheckoutAccessoryNotification; use Illuminate\Support\Facades\Notification; +use Tests\Concerns\TestsPermissionsRequirement; use Tests\TestCase; -class AccessoryCheckoutTest extends TestCase +class AccessoryCheckoutTest extends TestCase implements TestsPermissionsRequirement { - public function testCheckingOutAccessoryRequiresCorrectPermission() + public function testRequiresPermission() { $this->actingAsForApi(User::factory()->create()) ->postJson(route('api.accessories.checkout', Accessory::factory()->create())) diff --git a/tests/Support/CustomTestMacros.php b/tests/Support/CustomTestMacros.php index 993f449021..9c0caaf959 100644 --- a/tests/Support/CustomTestMacros.php +++ b/tests/Support/CustomTestMacros.php @@ -100,5 +100,26 @@ trait CustomTestMacros return $this; } ); + + TestResponse::macro( + 'assertMessagesContains', + function (array|string $keys) { + Assert::assertArrayHasKey('messages', $this, 'Response did not contain any messages'); + + if (is_string($keys)) { + $keys = [$keys]; + } + + foreach ($keys as $key) { + Assert::assertArrayHasKey( + $key, + $this['messages'], + "Response messages did not contain the key: {$key}" + ); + } + + return $this; + } + ); } }