snipe-it/tests/Feature/Assets/Api/StoreAssetTest.php

580 lines
21 KiB
PHP
Raw Normal View History

2023-11-01 14:49:59 -07:00
<?php
2024-06-04 10:48:53 -07:00
namespace Tests\Feature\Assets\Api;
2023-11-01 14:49:59 -07:00
2023-11-28 13:17:46 -08:00
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Company;
use App\Models\CustomField;
2023-11-28 13:17:46 -08:00
use App\Models\Location;
use App\Models\Statuslabel;
use App\Models\Supplier;
2023-11-01 14:49:59 -07:00
use App\Models\User;
2024-04-16 17:14:17 -07:00
use Illuminate\Support\Facades\Crypt;
use Illuminate\Testing\Fluent\AssertableJson;
2023-11-01 14:49:59 -07:00
use Tests\TestCase;
2024-06-03 16:53:15 -07:00
class StoreAssetTest extends TestCase
2023-11-01 14:49:59 -07:00
{
public function testRequiresPermissionToCreateAsset()
{
$this->actingAsForApi(User::factory()->create())
->postJson(route('api.assets.store'))
->assertForbidden();
}
2023-11-28 13:17:46 -08:00
public function testAllAssetAttributesAreStored()
{
$company = Company::factory()->create();
$location = Location::factory()->create();
$model = AssetModel::factory()->create();
$rtdLocation = Location::factory()->create();
$status = Statuslabel::factory()->create();
$supplier = Supplier::factory()->create();
$user = User::factory()->createAssets()->create();
$userAssigned = User::factory()->create();
$response = $this->actingAsForApi($user)
->postJson(route('api.assets.store'), [
'asset_eol_date' => '2024-06-02',
'asset_tag' => 'random_string',
2023-11-30 14:18:50 -08:00
'assigned_user' => $userAssigned->id,
2023-11-28 13:17:46 -08:00
'company_id' => $company->id,
'last_audit_date' => '2023-09-03',
'location_id' => $location->id,
'model_id' => $model->id,
'name' => 'A New Asset',
'notes' => 'Some notes',
'order_number' => '5678',
'purchase_cost' => '123.45',
'purchase_date' => '2023-09-02',
'requestable' => true,
'rtd_location_id' => $rtdLocation->id,
'serial' => '1234567890',
'status_id' => $status->id,
'supplier_id' => $supplier->id,
'warranty_months' => 10,
])
->assertOk()
->assertStatusMessageIs('success')
->json();
$asset = Asset::find($response['payload']['id']);
$this->assertTrue($asset->admin->is($user));
2023-11-28 13:17:46 -08:00
$this->assertEquals('2024-06-02', $asset->asset_eol_date);
$this->assertEquals('random_string', $asset->asset_tag);
2023-11-29 11:15:41 -08:00
$this->assertEquals($userAssigned->id, $asset->assigned_to);
2023-11-28 13:17:46 -08:00
$this->assertTrue($asset->company->is($company));
$this->assertEquals('2023-09-03 00:00:00', $asset->last_audit_date);
2023-11-30 14:18:50 -08:00
$this->assertTrue($asset->location->is($location));
2023-11-28 13:17:46 -08:00
$this->assertTrue($asset->model->is($model));
$this->assertEquals('A New Asset', $asset->name);
$this->assertEquals('Some notes', $asset->notes);
$this->assertEquals('5678', $asset->order_number);
$this->assertEquals('123.45', $asset->purchase_cost);
$this->assertTrue($asset->purchase_date->is('2023-09-02'));
$this->assertEquals('1', $asset->requestable);
$this->assertTrue($asset->defaultLoc->is($rtdLocation));
$this->assertEquals('1234567890', $asset->serial);
$this->assertTrue($asset->assetstatus->is($status));
$this->assertTrue($asset->supplier->is($supplier));
$this->assertEquals(10, $asset->warranty_months);
}
public function testSetsLastAuditDateToMidnightOfProvidedDate()
{
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'last_audit_date' => '2023-09-03',
'asset_tag' => '1234',
'model_id' => AssetModel::factory()->create()->id,
'status_id' => Statuslabel::factory()->create()->id,
])
->assertOk()
->assertStatusMessageIs('success');
$asset = Asset::find($response['payload']['id']);
$this->assertEquals('2023-09-03 00:00:00', $asset->last_audit_date);
}
public function testLastAuditDateCanBeNull()
{
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
// 'last_audit_date' => '2023-09-03 12:23:45',
'asset_tag' => '1234',
'model_id' => AssetModel::factory()->create()->id,
'status_id' => Statuslabel::factory()->create()->id,
])
->assertOk()
->assertStatusMessageIs('success');
$asset = Asset::find($response['payload']['id']);
$this->assertNull($asset->last_audit_date);
}
2024-03-25 13:46:22 -07:00
public function testNonDateUsedForLastAuditDateReturnsValidationError()
{
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'last_audit_date' => 'this-is-not-valid',
'asset_tag' => '1234',
'model_id' => AssetModel::factory()->create()->id,
'status_id' => Statuslabel::factory()->create()->id,
])
->assertStatusMessageIs('error');
$this->assertNotNull($response->json('messages.last_audit_date'));
}
public function testArchivedDepreciateAndPhysicalCanBeNull()
{
$model = AssetModel::factory()->ipadModel()->create();
$status = Statuslabel::factory()->create();
$this->settings->enableAutoIncrement();
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
'archive' => null,
'depreciate' => null,
'physical' => null
])
->assertOk()
->assertStatusMessageIs('success')
->json();
$asset = Asset::find($response['payload']['id']);
$this->assertEquals(0, $asset->archived);
$this->assertEquals(1, $asset->physical);
$this->assertEquals(0, $asset->depreciate);
}
public function testArchivedDepreciateAndPhysicalCanBeEmpty()
{
$model = AssetModel::factory()->ipadModel()->create();
$status = Statuslabel::factory()->create();
$this->settings->enableAutoIncrement();
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
'archive' => '',
'depreciate' => '',
'physical' => ''
])
->assertOk()
->assertStatusMessageIs('success')
->json();
$asset = Asset::find($response['payload']['id']);
$this->assertEquals(0, $asset->archived);
$this->assertEquals(1, $asset->physical);
$this->assertEquals(0, $asset->depreciate);
}
public function testAssetEolDateIsCalculatedIfPurchaseDateSet()
{
$model = AssetModel::factory()->mbp13Model()->create();
$status = Statuslabel::factory()->create();
$this->settings->enableAutoIncrement();
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'purchase_date' => '2021-01-01',
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('success')
->json();
$asset = Asset::find($response['payload']['id']);
$this->assertEquals('2024-01-01', $asset->asset_eol_date);
}
public function testAssetEolDateIsNotCalculatedIfPurchaseDateNotSet()
{
$model = AssetModel::factory()->mbp13Model()->create();
$status = Statuslabel::factory()->create();
$this->settings->enableAutoIncrement();
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('success')
->json();
$asset = Asset::find($response['payload']['id']);
$this->assertNull($asset->asset_eol_date);
}
2023-11-30 09:53:26 -08:00
public function testAssetEolExplicitIsSetIfAssetEolDateIsExplicitlySet()
{
$model = AssetModel::factory()->mbp13Model()->create();
$status = Statuslabel::factory()->create();
$this->settings->enableAutoIncrement();
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'asset_eol_date' => '2025-01-01',
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('success')
->json();
$asset = Asset::find($response['payload']['id']);
$this->assertEquals('2025-01-01', $asset->asset_eol_date);
$this->assertTrue($asset->eol_explicit);
}
2023-11-28 13:17:46 -08:00
public function testAssetGetsAssetTagWithAutoIncrement()
{
$model = AssetModel::factory()->create();
$status = Statuslabel::factory()->create();
$this->settings->enableAutoIncrement();
2023-11-30 09:53:26 -08:00
2023-11-28 13:17:46 -08:00
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
2023-11-30 09:53:26 -08:00
->assertStatusMessageIs('success')
->json();
$asset = Asset::find($response['payload']['id']);
2023-11-28 13:17:46 -08:00
$this->assertNotNull($asset->asset_tag);
}
public function testAssetCreationFailsWithNoAssetTagOrAutoIncrement()
{
$model = AssetModel::factory()->create();
$status = Statuslabel::factory()->create();
$this->settings->disableAutoIncrement();
$this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('error');
}
2024-04-25 14:07:56 -07:00
public function testStoresPeriodAsDecimalSeparatorForPurchaseCost()
{
2024-04-25 14:07:56 -07:00
$this->settings->set([
'default_currency' => 'USD',
'digit_separator' => '1,234.56',
]);
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'asset_tag' => 'random-string',
'model_id' => AssetModel::factory()->create()->id,
'status_id' => Statuslabel::factory()->create()->id,
// API accepts float
'purchase_cost' => 12.34,
])
->assertStatusMessageIs('success');
$asset = Asset::find($response['payload']['id']);
$this->assertEquals(12.34, $asset->purchase_cost);
}
2024-04-25 14:07:56 -07:00
public function testStoresPeriodAsCommaSeparatorForPurchaseCost()
{
2024-04-25 14:07:56 -07:00
$this->settings->set([
'default_currency' => 'EUR',
'digit_separator' => '1.234,56',
]);
$response = $this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'asset_tag' => 'random-string',
'model_id' => AssetModel::factory()->create()->id,
'status_id' => Statuslabel::factory()->create()->id,
2024-04-25 14:07:56 -07:00
// API also accepts string for comma separated values
'purchase_cost' => '12,34',
])
->assertStatusMessageIs('success');
$asset = Asset::find($response['payload']['id']);
2024-04-25 14:07:56 -07:00
$this->assertEquals(12.34, $asset->purchase_cost);
}
2023-11-28 13:17:46 -08:00
public function testUniqueSerialNumbersIsEnforcedWhenEnabled()
{
$model = AssetModel::factory()->create();
$status = Statuslabel::factory()->create();
$serial = '1234567890';
$this->settings->enableAutoIncrement();
$this->settings->enableUniqueSerialNumbers();
$this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
'serial' => $serial,
])
->assertOk()
->assertStatusMessageIs('success');
$this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
'serial' => $serial,
])
->assertOk()
->assertStatusMessageIs('error');
}
public function testUniqueSerialNumbersIsNotEnforcedWhenDisabled()
{
$model = AssetModel::factory()->create();
$status = Statuslabel::factory()->create();
$serial = '1234567890';
$this->settings->enableAutoIncrement();
$this->settings->disableUniqueSerialNumbers();
$this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
'serial' => $serial,
])
->assertOk()
->assertStatusMessageIs('success');
$this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'model_id' => $model->id,
'status_id' => $status->id,
'serial' => $serial,
])
->assertOk()
->assertStatusMessageIs('success');
}
public function testAssetTagsMustBeUniqueWhenUndeleted()
{
$model = AssetModel::factory()->create();
$status = Statuslabel::factory()->create();
$asset_tag = '1234567890';
$this->settings->disableAutoIncrement();
$this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'asset_tag' => $asset_tag,
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('success');
$this->actingAsForApi(User::factory()->superuser()->create())
->postJson(route('api.assets.store'), [
'asset_tag' => $asset_tag,
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('error');
}
public function testAssetTagsCanBeDuplicatedIfDeleted()
{
$model = AssetModel::factory()->create();
$status = Statuslabel::factory()->create();
$asset_tag = '1234567890';
$this->settings->disableAutoIncrement();
2023-12-04 10:47:46 -08:00
$response = $this->actingAsForApi(User::factory()->superuser()->create())
2023-11-28 13:17:46 -08:00
->postJson(route('api.assets.store'), [
'asset_tag' => $asset_tag,
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('success')
->json();
2023-12-04 10:47:46 -08:00
Asset::find($response['payload']['id'])->delete();
2023-11-28 13:17:46 -08:00
2023-12-04 10:47:46 -08:00
$this->actingAsForApi(User::factory()->superuser()->create())
2023-11-28 13:17:46 -08:00
->postJson(route('api.assets.store'), [
'asset_tag' => $asset_tag,
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('success');
}
2023-11-28 19:46:03 -08:00
public function testAnAssetCanBeCheckedOutToUserOnStore()
{
$model = AssetModel::factory()->create();
$status = Statuslabel::factory()->create();
$user = User::factory()->createAssets()->create();
$userAssigned = User::factory()->create();
$this->settings->enableAutoIncrement();
$response = $this->actingAsForApi($user)
->postJson(route('api.assets.store'), [
'assigned_user' => $userAssigned->id,
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('success')
->json();
$asset = Asset::find($response['payload']['id']);
$this->assertTrue($asset->admin->is($user));
2023-11-30 09:53:26 -08:00
$this->assertTrue($asset->checkedOutToUser());
2023-11-28 19:46:03 -08:00
$this->assertTrue($asset->assignedTo->is($userAssigned));
}
2023-11-28 20:11:20 -08:00
public function testAnAssetCanBeCheckedOutToLocationOnStore()
{
$model = AssetModel::factory()->create();
$status = Statuslabel::factory()->create();
$location = Location::factory()->create();
$user = User::factory()->createAssets()->create();
$this->settings->enableAutoIncrement();
$response = $this->actingAsForApi($user)
->postJson(route('api.assets.store'), [
'assigned_location' => $location->id,
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('success')
->json();
$asset = Asset::find($response['payload']['id']);
$this->assertTrue($asset->admin->is($user));
2023-11-30 09:53:26 -08:00
$this->assertTrue($asset->checkedOutToLocation());
2023-11-28 20:11:20 -08:00
$this->assertTrue($asset->location->is($location));
}
public function testAnAssetCanBeCheckedOutToAssetOnStore()
{
$model = AssetModel::factory()->create();
$status = Statuslabel::factory()->create();
$asset = Asset::factory()->create();
$user = User::factory()->createAssets()->create();
$this->settings->enableAutoIncrement();
$response = $this->actingAsForApi($user)
->postJson(route('api.assets.store'), [
'assigned_asset' => $asset->id,
'model_id' => $model->id,
'status_id' => $status->id,
])
->assertOk()
->assertStatusMessageIs('success')
->json();
$apiAsset = Asset::find($response['payload']['id']);
$this->assertTrue($apiAsset->admin->is($user));
2023-11-30 09:53:26 -08:00
$this->assertTrue($apiAsset->checkedOutToAsset());
2023-11-29 11:15:41 -08:00
// I think this makes sense, but open to a sanity check
$this->assertTrue($asset->assignedAssets()->find($response['payload']['id'])->is($apiAsset));
2023-11-28 20:11:20 -08:00
}
public function testCompanyIdNeedsToBeInteger()
{
$this->actingAsForApi(User::factory()->createAssets()->create())
->postJson(route('api.assets.store'), [
'company_id' => [1],
])
->assertStatusMessageIs('error')
->assertJson(function (AssertableJson $json) {
$json->has('messages.company_id')->etc();
});
}
2024-04-16 15:03:05 -07:00
public function testEncryptedCustomFieldCanBeStored()
{
2024-04-22 10:32:37 -07:00
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
2024-04-16 17:13:18 -07:00
$status = Statuslabel::factory()->create();
$field = CustomField::factory()->testEncrypted()->create();
$superuser = User::factory()->superuser()->create();
2024-04-16 17:13:18 -07:00
$assetData = Asset::factory()->hasEncryptedCustomField($field)->make();
$response = $this->actingAsForApi($superuser)
2024-04-16 17:13:18 -07:00
->postJson(route('api.assets.store'), [
$field->db_column_name() => 'This is encrypted field',
'model_id' => $assetData->model->id,
'status_id' => $status->id,
'asset_tag' => '1234',
])
->assertStatusMessageIs('success')
->assertOk()
->json();
2024-04-16 17:13:18 -07:00
$asset = Asset::findOrFail($response['payload']['id']);
2024-04-16 17:14:17 -07:00
$this->assertEquals('This is encrypted field', Crypt::decrypt($asset->{$field->db_column_name()}));
2024-04-16 15:03:05 -07:00
}
public function testPermissionNeededToStoreEncryptedField()
{
2024-04-16 17:13:18 -07:00
// @todo:
$this->markTestIncomplete();
$status = Statuslabel::factory()->create();
2024-04-16 15:03:05 -07:00
$field = CustomField::factory()->testEncrypted()->create();
$normal_user = User::factory()->editAssets()->create();
2024-04-16 17:13:18 -07:00
$assetData = Asset::factory()->hasEncryptedCustomField($field)->make();
$response = $this->actingAsForApi($normal_user)
2024-04-16 17:13:18 -07:00
->postJson(route('api.assets.store'), [
$field->db_column_name() => 'Some Other Value Entirely!',
'model_id' => $assetData->model->id,
'status_id' => $status->id,
'asset_tag' => '1234',
])
2024-04-16 17:13:18 -07:00
// @todo: this is 403 unauthorized
->assertStatusMessageIs('success')
->assertOk()
->assertMessagesAre('Asset updated successfully, but encrypted custom fields were not due to permissions')
->json();
2024-04-16 17:13:18 -07:00
$asset = Asset::findOrFail($response['payload']['id']);
2024-04-16 17:14:17 -07:00
$this->assertEquals('This is encrypted field', Crypt::decrypt($asset->{$field->db_column_name()}));
}
2023-11-01 14:49:59 -07:00
}