diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 05b4fe64a2..8c2b230d7e 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -89,31 +89,34 @@ class Asset extends Depreciable ]; protected $rules = [ - 'model_id' => ['required', 'integer', 'exists:models,id,deleted_at,NULL', 'not_array'], - 'status_id' => ['required', 'integer', 'exists:status_labels,id'], - 'asset_tag' => ['required', 'min:1', 'max:255', 'unique_undeleted:assets,asset_tag', 'not_array'], - 'name' => ['nullable', 'max:255'], - 'company_id' => ['nullable', 'integer', 'exists:companies,id'], - 'warranty_months' => ['nullable', 'numeric', 'digits_between:0,240'], - 'last_checkout' => ['nullable', 'date_format:Y-m-d H:i:s'], - 'last_checkin' => ['nullable', 'date_format:Y-m-d H:i:s'], - 'expected_checkin' => ['nullable', 'date'], - 'last_audit_date' => ['nullable', 'date_format:Y-m-d H:i:s'], - 'next_audit_date' => ['nullable', 'date'], + 'model_id' => ['required', 'integer', 'exists:models,id,deleted_at,NULL', 'not_array'], + 'status_id' => ['required', 'integer', 'exists:status_labels,id'], + 'asset_tag' => ['required', 'min:1', 'max:255', 'unique_undeleted:assets,asset_tag', 'not_array'], + 'name' => ['nullable', 'max:255'], + 'company_id' => ['nullable', 'integer', 'exists:companies,id'], + 'warranty_months' => ['nullable', 'numeric', 'digits_between:0,240'], + 'last_checkout' => ['nullable', 'date_format:Y-m-d H:i:s'], + 'last_checkin' => ['nullable', 'date_format:Y-m-d H:i:s'], + 'expected_checkin' => ['nullable', 'date'], + 'last_audit_date' => ['nullable', 'date_format:Y-m-d H:i:s'], + 'next_audit_date' => ['nullable', 'date'], //'after:last_audit_date'], - 'location_id' => ['nullable', 'exists:locations,id'], - 'rtd_location_id' => ['nullable', 'exists:locations,id'], - 'purchase_date' => ['nullable', 'date', 'date_format:Y-m-d'], - 'serial' => ['nullable', 'unique_undeleted:assets,serial'], - 'purchase_cost' => ['nullable', 'numeric', 'gte:0'], - 'supplier_id' => ['nullable', 'exists:suppliers,id'], - 'asset_eol_date' => ['nullable', 'date'], - 'eol_explicit' => ['nullable', 'boolean'], - 'byod' => ['nullable', 'boolean'], - 'order_number' => ['nullable', 'string', 'max:191'], - 'notes' => ['nullable', 'string', 'max:65535'], - 'assigned_to' => ['nullable', 'integer'], - 'requestable' => ['nullable', 'boolean'], + 'location_id' => ['nullable', 'exists:locations,id'], + 'rtd_location_id' => ['nullable', 'exists:locations,id'], + 'purchase_date' => ['nullable', 'date', 'date_format:Y-m-d'], + 'serial' => ['nullable', 'unique_undeleted:assets,serial'], + 'purchase_cost' => ['nullable', 'numeric', 'gte:0'], + 'supplier_id' => ['nullable', 'exists:suppliers,id'], + 'asset_eol_date' => ['nullable', 'date'], + 'eol_explicit' => ['nullable', 'boolean'], + 'byod' => ['nullable', 'boolean'], + 'order_number' => ['nullable', 'string', 'max:191'], + 'notes' => ['nullable', 'string', 'max:65535'], + 'assigned_to' => ['nullable', 'integer'], + 'requestable' => ['nullable', 'boolean'], + 'assigned_user' => ['nullable', 'exists:users,id,deleted_at,NULL'], + 'assigned_location' => ['nullable', 'exists:locations,id,deleted_at,NULL'], + 'assigned_asset' => ['nullable', 'exists:assets,id,deleted_at,NULL'] ]; diff --git a/database/factories/LocationFactory.php b/database/factories/LocationFactory.php index 6db268e8c1..94c0efe966 100644 --- a/database/factories/LocationFactory.php +++ b/database/factories/LocationFactory.php @@ -25,4 +25,9 @@ class LocationFactory extends Factory 'image' => rand(1, 9).'.jpg', ]; } + + public function deleted(): self + { + return $this->state(['deleted_at' => $this->faker->dateTime()]); + } } diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index cb1ccd89b5..3213dbb285 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -299,4 +299,9 @@ class UserFactory extends Factory ]; }); } + + public function deleted(): self + { + return $this->state(['deleted_at' => $this->faker->dateTime()]); + } } diff --git a/tests/Feature/Api/Assets/AssetUpdateTest.php b/tests/Feature/Api/Assets/AssetUpdateTest.php index baff41e5cd..85c2a9b0af 100644 --- a/tests/Feature/Api/Assets/AssetUpdateTest.php +++ b/tests/Feature/Api/Assets/AssetUpdateTest.php @@ -306,4 +306,121 @@ class AssetUpdateTest extends TestCase $asset->refresh(); $this->assertEquals("encrypted value should not change", Crypt::decrypt($asset->{$field->db_column_name()})); } + + public function testCheckoutToUserOnAssetUpdate() + { + $asset = Asset::factory()->create(); + $user = User::factory()->editAssets()->create(); + $assigned_user = User::factory()->create(); + + $response = $this->actingAsForApi($user) + ->patchJson(route('api.assets.update', $asset->id), [ + 'assigned_user' => $assigned_user->id, + ]) + ->assertOk() + ->assertStatusMessageIs('success') + ->json(); + + $asset->refresh(); + $this->assertEquals($assigned_user->id, $asset->assigned_to); + $this->assertEquals($asset->assigned_type, 'App\Models\User'); + } + + public function testCheckoutToDeletedUserFailsOnAssetUpdate() + { + $asset = Asset::factory()->create(); + $user = User::factory()->editAssets()->create(); + $assigned_user = User::factory()->deleted()->create(); + + $this->actingAsForApi($user) + ->patchJson(route('api.assets.update', $asset->id), [ + 'assigned_user' => $assigned_user->id, + ]) + ->assertOk() + ->assertStatusMessageIs('error') + ->json(); + + $asset->refresh(); + $this->assertNull($asset->assigned_to); + $this->assertNull($asset->assigned_type); + } + + public function testCheckoutToLocationOnAssetUpdate() + { + $asset = Asset::factory()->create(); + $user = User::factory()->editAssets()->create(); + $assigned_location = Location::factory()->create(); + + $this->actingAsForApi($user) + ->patchJson(route('api.assets.update', $asset->id), [ + 'assigned_location' => $assigned_location->id, + ]) + ->assertOk() + ->assertStatusMessageIs('success') + ->json(); + + $asset->refresh(); + $this->assertEquals($assigned_location->id, $asset->assigned_to); + $this->assertEquals($asset->assigned_type, 'App\Models\Location'); + + } + + public function testCheckoutToDeletedLocationFailsOnAssetUpdate() + { + $asset = Asset::factory()->create(); + $user = User::factory()->editAssets()->create(); + $assigned_location = Location::factory()->deleted()->create(); + + $this->actingAsForApi($user) + ->patchJson(route('api.assets.update', $asset->id), [ + 'assigned_location' => $assigned_location->id, + ]) + ->assertOk() + ->assertStatusMessageIs('error') + ->json(); + + $asset->refresh(); + $this->assertNull($asset->assigned_to); + $this->assertNull($asset->assigned_type); + } + + public function testCheckoutAssetOnAssetUpdate() + { + $asset = Asset::factory()->create(); + $user = User::factory()->editAssets()->create(); + $assigned_asset = Asset::factory()->create(); + + $this->actingAsForApi($user) + ->patchJson(route('api.assets.update', $asset->id), [ + 'assigned_asset' => $assigned_asset->id, + 'checkout_to_type' => 'user', + ]) + ->assertOk() + ->assertStatusMessageIs('success') + ->json(); + + $asset->refresh(); + $this->assertEquals($assigned_asset->id, $asset->assigned_to); + $this->assertEquals($asset->assigned_type, 'App\Models\Asset'); + + } + + public function testCheckoutToDeletedAssetFailsOnAssetUpdate() + { + $asset = Asset::factory()->create(); + $user = User::factory()->editAssets()->create(); + $assigned_asset = Asset::factory()->deleted()->create(); + + $this->actingAsForApi($user) + ->patchJson(route('api.assets.update', $asset->id), [ + 'assigned_asset' => $assigned_asset->id, + ]) + ->assertOk() + ->assertStatusMessageIs('error') + ->json(); + + $asset->refresh(); + $this->assertNull($asset->assigned_to); + $this->assertNull($asset->assigned_type); + } }