Added additional helper files to assetmodel importer

Signed-off-by: snipe <snipe@snipe.net>
This commit is contained in:
snipe 2024-11-12 22:40:00 +00:00
parent 22c79d8e1b
commit 48713cbddf
9 changed files with 266 additions and 36 deletions

View file

@ -177,6 +177,9 @@ class ImportController extends Controller
case 'asset':
$redirectTo = 'hardware.index';
break;
case 'assetmodel':
$redirectTo = 'models.index';
break;
case 'accessory':
$redirectTo = 'accessories.index';
break;

View file

@ -59,18 +59,22 @@ class AssetModelImporter extends ItemImporter
$this->item['manufacturer'] = trim($this->findCsvMatch($row, 'manufacturer'));
$this->item['min_amt'] = trim($this->findCsvMatch($row, 'min_amt'));
$this->item['model_number'] = trim($this->findCsvMatch($row, 'model_number'));
$this->item['eol'] = trim($this->findCsvMatch($row, 'eol'));
$this->item['notes'] = trim($this->findCsvMatch($row, 'notes'));
$this->item['user_id'] = auth()->id();
$this->item['created_by'] = auth()->id();
$this->item['requestable'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'))) == 1) ? '1' : 0;
$assetmodel->requestable = $this->item['requestable'];
if (!empty($this->item['category'])) {
if ($category = $this->createOrFetchCategory($row, 'category')) {
$this->item['category_id'] = $category->id;
if ($category = $this->createOrFetchCategory($this->item['category'])) {
$this->item['category_id'] = $category;
}
}
if (!empty($this->item['manufacturer'])) {
if ($manufacturer = $this->createOrFetchManufacturer($row, 'manufacturer')) {
$this->item['manufacturer_id'] = $manufacturer->id;
if ($manufacturer = $this->createOrFetchManufacturer($this->item['manufacturer'])) {
$this->item['manufacturer_id'] = $manufacturer;
}
}

View file

@ -287,6 +287,7 @@ class ItemImporter extends Importer
$classname = class_basename(get_class($this));
$item_type = strtolower(substr($classname, 0, strpos($classname, 'Importer')));
// If we're importing asset models only (without attached assets), override the category type to asset
if ($item_type == 'assetmodel') {
$item_type = 'asset';
}
@ -302,7 +303,7 @@ class ItemImporter extends Importer
if ($category) {
$this->log('A matching category: '.$asset_category.' already exists');
$this->log('A matching category: '.$category->name.' already exists');
return $category->id;
}

View file

@ -346,7 +346,7 @@ class Importer extends Component
'notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]),
'min_amt' => trans('mail.min_QTY'),
'fieldset' => trans('admin/models/general.fieldset'),
'category_type' => 'category type',
'eol' => 'eol',
];
@ -570,15 +570,13 @@ class Importer extends Component
$this->message_type = 'success';
unset($this->files);
return;
}
$this->message = trans('admin/hardware/message.import.file_delete_error');
$this->message_type = 'danger';
}
}
}
$this->message = trans('admin/hardware/message.import.file_delete_error');
$this->message_type = 'danger';
}
public function clearMessage()

View file

@ -143,4 +143,23 @@ class ImportFactory extends Factory
return $attributes;
});
}
/**
* Create an asset model import type.
*
* @return static
*/
public function assetmodel()
{
return $this->state(function (array $attributes) {
$fileBuilder = Importing\AssetModelsImportFileBuilder::new();
$attributes['name'] = "{$attributes['name']} Asset Model";
$attributes['import_type'] = 'assetmodel';
$attributes['header_row'] = $fileBuilder->toCsv()[0];
$attributes['first_row'] = $fileBuilder->firstRow();
return $attributes;
});
}
}

View file

@ -177,7 +177,7 @@
</p>
@endif
@if ($activeFile->import_type != 'location' && $activeFile->import_type == 'assetmodel' && $update)
@if ($this->activeFile->import_type != 'location' && $this->activeFile->import_type == 'assetmodel' && $update)
<label class="form-control">
<input type="checkbox" name="send_welcome" data-livewire-component="{{ $this->getId() }}" wire:model.live="send_welcome">
{{ trans('general.send_welcome_email_to_users') }}

View file

@ -1,22 +1,23 @@
Category,Category Type,Manufacturer,Name,Notes,Model Number,Fieldset
Laptops,asset,Berge Inc,Test Model 1,,1786VM80X07,Laptops and Desktops
Laptops,asset,"Botsford, Boyle and Herzog",Test Model 2,ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra diam vitae quam suspendisse potenti nullam,9351IS25A51,Laptops and Desktops
Laptops,asset,Pollich LLC,Test Model 3,,9929FR08W85,Laptops and Desktops
Laptops,asset,Walker-Towne,Test Model 4,neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus,9139KQ78G81,Laptops and Desktops
Laptops,asset,Berge Inc,Test Model 5,turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at turpis a pede,0910VB28Q61,Laptops and Desktops
Laptops,asset,"Heaney, Altenwerth and Emmerich",Test Model 6,,7375EM02N97,Laptops and Desktops
Laptops,asset,"Romaguera, Goldner and Crooks",Test Model 7,blandit non interdum in ante vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae,,Laptops and Desktops
Laptops,asset,Watsica LLC,Test Model 8,sapien urna pretium nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in,,Laptops and Desktops
Laptops,asset,"Fritsch, Sauer and Conn",Test Model 9,orci luctus et ultrices posuere cubilia curae duis faucibus accumsan odio curabitur,,Laptops and Desktops
Laptops,asset,"Upton, Feil and Jast",Test Model 10,velit vivamus vel nulla eget eros elementum pellentesque quisque porta volutpat,,Laptops and Desktops
Laptops,asset,Berge Inc,Test Model 11,sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta volutpat quam pede lobortis ligula sit,,Laptops and Desktops
Laptops,asset,"Kutch, Johnson and Olson",Test Model 12,curae mauris viverra diam vitae quam suspendisse potenti nullam porttitor lacus at turpis donec posuere metus vitae ipsum aliquam non,,Laptops and Desktops
Laptops,asset,Mosciski Inc,Test Model 13,molestie hendrerit at vulputate vitae nisl aenean lectus pellentesque eget nunc donec quis orci,,Laptops and Desktops
Laptops,asset,Mosciski Inc,Test Model 14,egestas metus aenean fermentum donec ut mauris eget massa tempor convallis nulla neque libero convallis eget eleifend,,Laptops and Desktops
Laptops,asset,"Upton, Feil and Jast",Test Model 15,,,Laptops and Desktops
Laptops,asset,"Romaguera, Goldner and Crooks",Test Model 16,dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce,2315CN41G71,Laptops and Desktops
Laptops,asset,Abernathy-Stamm,Test Model 17,maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus,6080UE59E09,Laptops and Desktops
Laptops,asset,Mosciski Inc,Test Model 18,,5505YF23M46,Laptops and Desktops
Laptops,asset,Walker-Towne,Test Model 19,,8673QP30R80,Laptops and Desktops
Mobile Phones,asset,"Heaney, Altenwerth and Emmerich",Test Model 20,nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in congue etiam justo etiam pretium,9088XV67Q94,Mobile Devices
Mobile Phones,asset,Okuneva Group,Test One,quis libero nullam sit amet turpis elementum ligula vehicula consequat morbi a ipsum integer a nibh in quis,,Mobile Devices
Name,Category,Manufacturer,Notes,Model Number,Fieldset,Requestable
Changed Test Model,Laptops,Berge Inc,"Sphinx of black quartz, judge my vow",1786VM80X07,Laptops and Desktops,Y
Test Model 2,Laptops,"Botsford, Boyle and Herzog",ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra diam vitae quam suspendisse potenti nullam,9351IS25A51,Laptops and Desktops,Y
Test Model 3,Laptops,Pollich LLC,,9929FR08W85,Laptops and Desktops,Y
Test Model 4,Laptops,Walker-Towne,neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus,9139KQ78G81,Laptops and Desktops,Y
Test Model 5,Laptops,Berge Inc,turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at turpis a pede,0910VB28Q61,Laptops and Desktops,Y
Test Model 6,Laptops,"Heaney, Altenwerth and Emmerich",,7375EM02N97,Laptops and Desktops,Y
Test Model 7,Desktops,"Romaguera, Goldner and Crooks",Test Updated Text,,Laptops and Desktops,Y
Test Model 8,Laptops,Watsica LLC,sapien urna pretium nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in,,Laptops and Desktops,Y
Test Model 9,Laptops,"Fritsch, Sauer and Conn",orci luctus et ultrices posuere cubilia curae duis faucibus accumsan odio curabitur,,Laptops and Desktops,Y
Test Model 10,Laptops,"Upton, Feil and Jast",velit vivamus vel nulla eget eros elementum pellentesque quisque porta volutpat,,Laptops and Desktops,Y
Test Model 11,Laptops,Berge Inc,sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta volutpat quam pede lobortis ligula sit,,Laptops and Desktops,Y
Test Model 12,Laptops,"Kutch, Johnson and Olson",curae mauris viverra diam vitae quam suspendisse potenti nullam porttitor lacus at turpis donec posuere metus vitae ipsum aliquam non,,Laptops and Desktops,Y
Test Model 13,Laptops,Mosciski Inc,molestie hendrerit at vulputate vitae nisl aenean lectus pellentesque eget nunc donec quis orci,,Laptops and Desktops,Y
Test Model 14,Laptops,Mosciski Inc,egestas metus aenean fermentum donec ut mauris eget massa tempor convallis nulla neque libero convallis eget eleifend,,Laptops and Desktops,N
Test Model 15,Laptops,"Upton, Feil and Jast",,,Laptops and Desktops,N
Test Model 16,Laptops,"Romaguera, Goldner and Crooks",dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce,2315CN41G71,Laptops and Desktops,N
Test Model 17,Laptops,Abernathy-Stamm,maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus,6080UE59E09,Laptops and Desktops,N
Test Model 18,Laptops,Mosciski Inc,,5505YF23M46,Laptops and Desktops,N
Test Model 19,Laptops,Walker-Towne,,8673QP30R80,Laptops and Desktops,Y
Test Model 20,Mobile Phones,"Heaney, Altenwerth and Emmerich",nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in congue etiam justo etiam pretium,9088XV67Q94,Mobile Devices,Y
Test One,Mobile Phones,Okuneva Group,quis libero nullam sit amet turpis elementum ligula vehicula consequat morbi a ipsum integer a nibh in quis,,Mobile Devices,Y
Test Missing Category,,,orci luctus et ultrices posuere cubilia curae duis faucibus accumsan odio curabitur,,,
1 Name Category Type Category Manufacturer Notes Model Number Fieldset Requestable
2 Test Model 1 Changed Test Model asset Laptops Berge Inc Sphinx of black quartz, judge my vow 1786VM80X07 Laptops and Desktops Y
3 Test Model 2 asset Laptops Botsford, Boyle and Herzog ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra diam vitae quam suspendisse potenti nullam 9351IS25A51 Laptops and Desktops Y
4 Test Model 3 asset Laptops Pollich LLC 9929FR08W85 Laptops and Desktops Y
5 Test Model 4 asset Laptops Walker-Towne neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus 9139KQ78G81 Laptops and Desktops Y
6 Test Model 5 asset Laptops Berge Inc turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc proin at turpis a pede 0910VB28Q61 Laptops and Desktops Y
7 Test Model 6 asset Laptops Heaney, Altenwerth and Emmerich 7375EM02N97 Laptops and Desktops Y
8 Test Model 7 asset Laptops Desktops Romaguera, Goldner and Crooks blandit non interdum in ante vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae Test Updated Text Laptops and Desktops Y
9 Test Model 8 asset Laptops Watsica LLC sapien urna pretium nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in Laptops and Desktops Y
10 Test Model 9 asset Laptops Fritsch, Sauer and Conn orci luctus et ultrices posuere cubilia curae duis faucibus accumsan odio curabitur Laptops and Desktops Y
11 Test Model 10 asset Laptops Upton, Feil and Jast velit vivamus vel nulla eget eros elementum pellentesque quisque porta volutpat Laptops and Desktops Y
12 Test Model 11 asset Laptops Berge Inc sed nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta volutpat quam pede lobortis ligula sit Laptops and Desktops Y
13 Test Model 12 asset Laptops Kutch, Johnson and Olson curae mauris viverra diam vitae quam suspendisse potenti nullam porttitor lacus at turpis donec posuere metus vitae ipsum aliquam non Laptops and Desktops Y
14 Test Model 13 asset Laptops Mosciski Inc molestie hendrerit at vulputate vitae nisl aenean lectus pellentesque eget nunc donec quis orci Laptops and Desktops Y
15 Test Model 14 asset Laptops Mosciski Inc egestas metus aenean fermentum donec ut mauris eget massa tempor convallis nulla neque libero convallis eget eleifend Laptops and Desktops N
16 Test Model 15 asset Laptops Upton, Feil and Jast Laptops and Desktops N
17 Test Model 16 asset Laptops Romaguera, Goldner and Crooks dui luctus rutrum nulla tellus in sagittis dui vel nisl duis ac nibh fusce 2315CN41G71 Laptops and Desktops N
18 Test Model 17 asset Laptops Abernathy-Stamm maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus 6080UE59E09 Laptops and Desktops N
19 Test Model 18 asset Laptops Mosciski Inc 5505YF23M46 Laptops and Desktops N
20 Test Model 19 asset Laptops Walker-Towne 8673QP30R80 Laptops and Desktops Y
21 Test Model 20 asset Mobile Phones Heaney, Altenwerth and Emmerich nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in congue etiam justo etiam pretium 9088XV67Q94 Mobile Devices Y
22 Test One asset Mobile Phones Okuneva Group quis libero nullam sit amet turpis elementum ligula vehicula consequat morbi a ipsum integer a nibh in quis Mobile Devices Y
23 Test Missing Category orci luctus et ultrices posuere cubilia curae duis faucibus accumsan odio curabitur

View file

@ -0,0 +1,146 @@
<?php
namespace Tests\Feature\Importing\Api;
use App\Models\Category;
use App\Models\AssetModel;
use App\Models\User;
use App\Models\Import;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Testing\TestResponse;
use PHPUnit\Framework\Attributes\Test;
use Tests\Concerns\TestsPermissionsRequirement;
use Tests\Support\Importing\CleansUpImportFiles;
use Tests\Support\Importing\AssetModelsImportFileBuilder as ImportFileBuilder;
class ImportAssetModelsTest extends ImportDataTestCase implements TestsPermissionsRequirement
{
use CleansUpImportFiles;
use WithFaker;
protected function importFileResponse(array $parameters = []): TestResponse
{
if (!array_key_exists('import-type', $parameters)) {
$parameters['import-type'] = 'assetmodel';
}
return parent::importFileResponse($parameters);
}
#[Test]
public function testRequiresPermission()
{
$this->actingAsForApi(User::factory()->create());
$this->importFileResponse(['import' => 44])->assertForbidden();
}
#[Test]
public function userWithImportAssetsPermissionCanImportUsers(): void
{
$this->actingAsForApi(User::factory()->canImport()->create());
$import = Import::factory()->users()->create();
$this->importFileResponse(['import' => $import->id])->assertOk();
}
#[Test]
public function importAssetModels(): void
{
$importFileBuilder = ImportFileBuilder::new();
$row = $importFileBuilder->firstRow();
$import = Import::factory()->assetmodel()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
$this->actingAsForApi(User::factory()->superuser()->create());
$this->importFileResponse(['import' => $import->id, 'send-welcome' => 0])
->assertOk()
->assertExactJson([
'payload' => null,
'status' => 'success',
'messages' => ['redirect_url' => route('models.index')]
]);
$newAssetModel = AssetModel::query()
->with(['category'])
->where('name', $row['name'])
->sole();
$this->assertEquals($row['name'], $newAssetModel->name);
$this->assertEquals($row['model_number'], $newAssetModel->model_number);
}
#[Test]
public function willIgnoreUnknownColumnsWhenFileContainsUnknownColumns(): void
{
$row = ImportFileBuilder::new()->definition();
$row['unknownColumnInCsvFile'] = 'foo';
$importFileBuilder = new ImportFileBuilder([$row]);
$this->actingAsForApi(User::factory()->superuser()->create());
$import = Import::factory()->assetmodel()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
$this->importFileResponse(['import' => $import->id])->assertOk();
}
#[Test]
public function whenRequiredColumnsAreMissingInImportFile(): void
{
$importFileBuilder = ImportFileBuilder::new(['name' => ''])->forget(['category']);
$import = Import::factory()->assetmodel()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
$this->actingAsForApi(User::factory()->superuser()->create());
$this->importFileResponse(['import' => $import->id])
->assertInternalServerError()
->assertExactJson([
'status' => 'import-errors',
'payload' => null,
'messages' => [
'' => [
'name' => ['The name field is required.'],
]
]
]);
$newAssetModels = AssetModel::query()
->where('name', $importFileBuilder->firstRow()['name'])
->get();
$this->assertCount(0, $newAssetModels);
}
#[Test]
public function updateAssetModelFromImport(): void
{
$assetmodel = AssetModel::factory()->create()->refresh();
$importFileBuilder = ImportFileBuilder::new(['name' => Str::random(), 'model_number' => Str::random()]);
$row = $importFileBuilder->firstRow();
$import = Import::factory()->assetmodel()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
$this->actingAsForApi(User::factory()->superuser()->create());
$this->importFileResponse(['import' => $import->id, 'import-update' => true])->assertOk();
$updatedAssetmodel = AssetModel::query()->find($assetmodel->id);
$updatedAttributes = [
'name',
'model_number'
];
$this->assertEquals($row['model_number'], $updatedAssetmodel->model_number);
$this->assertEquals(
Arr::except($assetmodel->attributesToArray(), $updatedAttributes),
Arr::except($updatedAssetmodel->attributesToArray(), $updatedAttributes),
);
}
}

View file

@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace Tests\Support\Importing;
use App\Models\Category;
use Illuminate\Support\Str;
/**
* Build a users import file at runtime for testing.
*
* @template Row of array{
* name?: string,
* manufacturer?: string,
* category?: string,
* model_number?: string,
* requestable?: int,
* }
*
* @extends FileBuilder<Row>
*/
class AssetModelsImportFileBuilder extends FileBuilder
{
/**
* @inheritdoc
*/
protected function getDictionary(): array
{
return [
'name' => 'Name',
'category' => 'Category',
'manufacturer' => 'Manufacturer',
'model_number' => 'Model Number',
'fieldset' => 'Fieldset',
'eol' => 'EOL',
'min_amt' => 'Min Amount',
'notes' => 'Notes',
'requestable' => 'Requestable',
];
}
/**
* @inheritdoc
*/
public function definition(): array
{
$faker = fake();
return [
'name' => $faker->catchPhrase,
'category' => Str::random(),
'model_number' => $faker->creditCardNumber(),
'notes' => $faker->sentence(5),
];
}
}