actingAsForApi(User::factory()->create()) ->postJson(route('api.asset.checkout', Asset::factory()->create()), [ 'checkout_to_type' => 'user', 'assigned_user' => User::factory()->create()->id, ]) ->assertForbidden(); } public function testNonExistentAssetCannotBeCheckedOut(): void { $this->actingAsForApi(User::factory()->checkoutAssets()->create()) ->postJson(route('api.asset.checkout', 1000), [ 'checkout_to_type' => 'user', 'assigned_user' => User::factory()->create()->id, ]) ->assertStatusMessageIs('error'); } public function testAssetNotAvailableForCheckoutCannotBeCheckedOut(): void { $assetAlreadyCheckedOut = Asset::factory()->assignedToUser()->create(); $this->actingAsForApi(User::factory()->checkoutAssets()->create()) ->postJson(route('api.asset.checkout', $assetAlreadyCheckedOut), [ 'checkout_to_type' => 'user', 'assigned_user' => User::factory()->create()->id, ]) ->assertStatusMessageIs('error'); } public function testAssetCannotBeCheckedOutToItself(): void { $asset = Asset::factory()->create(); $this->actingAsForApi(User::factory()->checkoutAssets()->create()) ->postJson(route('api.asset.checkout', $asset), [ 'checkout_to_type' => 'asset', 'assigned_asset' => $asset->id, ]) ->assertStatusMessageIs('error'); } public function testValidationWhenCheckingOutAsset(): void { $this->actingAsForApi(User::factory()->checkoutAssets()->create()) ->postJson(route('api.asset.checkout', Asset::factory()->create()), []) ->assertStatusMessageIs('error'); Event::assertNotDispatched(CheckoutableCheckedOut::class); } public function testCannotCheckoutAcrossCompaniesWhenFullCompanySupportEnabled(): void { $this->markTestIncomplete('This is not implemented'); } /** * This data provider contains checkout targets along with the * asset's expected location after the checkout process. */ public static function checkoutTargets(): array { return [ 'Checkout to User' => [ function () { $userLocation = Location::factory()->create(); $user = User::factory()->for($userLocation)->create(); return [ 'checkout_type' => 'user', 'target' => $user, 'expected_location' => $userLocation, ]; } ], 'Checkout to User without location set' => [ function () { $userLocation = Location::factory()->create(); $user = User::factory()->for($userLocation)->create(['location_id' => null]); return [ 'checkout_type' => 'user', 'target' => $user, 'expected_location' => null, ]; } ], 'Checkout to Asset with location set' => [ function () { $rtdLocation = Location::factory()->create(); $location = Location::factory()->create(); $asset = Asset::factory()->for($location)->for($rtdLocation, 'defaultLoc')->create(); return [ 'checkout_type' => 'asset', 'target' => $asset, 'expected_location' => $location, ]; } ], 'Checkout to Asset without location set' => [ function () { $rtdLocation = Location::factory()->create(); $asset = Asset::factory()->for($rtdLocation, 'defaultLoc')->create(['location_id' => null]); return [ 'checkout_type' => 'asset', 'target' => $asset, 'expected_location' => null, ]; } ], 'Checkout to Location' => [ function () { $location = Location::factory()->create(); return [ 'checkout_type' => 'location', 'target' => $location, 'expected_location' => $location, ]; } ], ]; } #[DataProvider('checkoutTargets')] public function testAssetCanBeCheckedOut($data): void { ['checkout_type' => $type, 'target' => $target, 'expected_location' => $expectedLocation] = $data(); $newStatus = Statuslabel::factory()->readyToDeploy()->create(); $asset = Asset::factory()->forLocation()->create(); $admin = User::factory()->checkoutAssets()->create(); $this->actingAsForApi($admin) ->postJson(route('api.asset.checkout', $asset), [ 'checkout_to_type' => $type, 'assigned_'.$type => $target->id, 'status_id' => $newStatus->id, 'checkout_at' => '2024-04-01', 'expected_checkin' => '2024-04-08', 'name' => 'Changed Name', 'note' => 'Here is a cool note!', ]) ->assertOk(); $asset->refresh(); $this->assertTrue($asset->assignedTo()->is($target)); $this->assertEquals('Changed Name', $asset->name); $this->assertTrue($asset->assetstatus->is($newStatus)); $this->assertEquals('2024-04-01 00:00:00', $asset->last_checkout); $this->assertEquals('2024-04-08 00:00:00', (string) $asset->expected_checkin); $expectedLocation ? $this->assertTrue($asset->location->is($expectedLocation)) : $this->assertNull($asset->location); Event::assertDispatched(CheckoutableCheckedOut::class, 1); Event::assertDispatched(function (CheckoutableCheckedOut $event) use ($admin, $asset, $target) { $this->assertTrue($event->checkoutable->is($asset)); $this->assertTrue($event->checkedOutTo->is($target)); $this->assertTrue($event->checkedOutBy->is($admin)); $this->assertEquals('Here is a cool note!', $event->note); return true; }); } public function testLicenseSeatsAreAssignedToUserUponCheckout(): void { $this->markTestIncomplete('This is not implemented'); } public function testLastCheckoutUsesCurrentDateIfNotProvided(): void { $asset = Asset::factory()->create(['last_checkout' => now()->subMonth()]); $this->actingAsForApi(User::factory()->checkoutAssets()->create()) ->postJson(route('api.asset.checkout', $asset), [ 'checkout_to_type' => 'user', 'assigned_user' => User::factory()->create()->id, ]); $asset->refresh(); $this->assertTrue(Carbon::parse($asset->last_checkout)->diffInSeconds(now()) < 2); } }