From 5d46d9072534bc31fac3842202c73b57a2b79fa2 Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 2 Jun 2025 04:11:54 +0100 Subject: [PATCH 1/4] Added category importer Signed-off-by: snipe --- app/Helpers/Helper.php | 2 + app/Http/Controllers/Api/ImportController.php | 3 + app/Importer/CategoryImporter.php | 99 +++++++++++++ app/Importer/ItemImporter.php | 2 +- app/Livewire/Importer.php | 17 +++ database/factories/ImportFactory.php | 14 ++ resources/views/livewire/importer.blade.php | 2 +- sample_csvs/categories-sample.csv | 16 +++ .../Importing/Api/ImportCategoriesTest.php | 135 ++++++++++++++++++ .../Importing/CategoriesImportFileBuilder.php | 56 ++++++++ 10 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 app/Importer/CategoryImporter.php create mode 100644 sample_csvs/categories-sample.csv create mode 100644 tests/Feature/Importing/Api/ImportCategoriesTest.php create mode 100644 tests/Support/Importing/CategoriesImportFileBuilder.php diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index ddd828c6f4..f544f2bc36 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1329,6 +1329,8 @@ class Helper return 'fa-solid fa-store'; case 'manufacturer': return 'fa-solid fa-building'; + case 'category': + return 'fa-solid fa-table-columns'; } } diff --git a/app/Http/Controllers/Api/ImportController.php b/app/Http/Controllers/Api/ImportController.php index b70d4f218e..c18df26683 100644 --- a/app/Http/Controllers/Api/ImportController.php +++ b/app/Http/Controllers/Api/ImportController.php @@ -240,6 +240,9 @@ class ImportController extends Controller case 'manufacturer': $redirectTo = 'manufacturers.index'; break; + case 'category': + $redirectTo = 'categories.index'; + break; } if ($errors) { //Failure diff --git a/app/Importer/CategoryImporter.php b/app/Importer/CategoryImporter.php new file mode 100644 index 0000000000..c8d93f355a --- /dev/null +++ b/app/Importer/CategoryImporter.php @@ -0,0 +1,99 @@ +createCategoryIfNotExists($row); + } + + /** + * Create a supplier if a duplicate does not exist. + * @todo Investigate how this should interact with Importer::createCategoryIfNotExists + * + * @author A. Gianotto + * @since 6.1.0 + * @param array $row + */ + public function createCategoryIfNotExists(array $row) + { + + $editingCategory = false; + + $supplier = Category::where('name', '=', $this->findCsvMatch($row, 'name'))->first(); + + if ($this->findCsvMatch($row, 'id')!='') { + // Override supplier if an ID was given + \Log::debug('Finding supplier by ID: '.$this->findCsvMatch($row, 'id')); + $supplier = Category::find($this->findCsvMatch($row, 'id')); + } + + + if ($supplier) { + if (! $this->updating) { + $this->log('A matching Category '.$this->item['name'].' already exists'); + return; + } + + $this->log('Updating Category'); + $editingCategory = true; + } else { + $this->log('No Matching Category, Create a new one'); + $supplier = new Category; + $supplier->created_by = auth()->id(); + } + + // Pull the records from the CSV to determine their values + $this->item['name'] = trim($this->findCsvMatch($row, 'name')); + $this->item['notes'] = trim($this->findCsvMatch($row, 'notes')); + $this->item['eula_text'] = trim($this->findCsvMatch($row, 'eula_text')); + $this->item['category_type'] = trim($this->findCsvMatch($row, 'category_type')); + $this->item['use_default_eula'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'use_default_eula'))) == 1) ? 1 : 0; + $this->item['require_acceptance'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'require_acceptance'))) == 1) ? 1 : 0; + $this->item['checkin_email'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'checkin_email'))) == 1) ? 1 : 0; + + + Log::debug('Item array is: '); + Log::debug(print_r($this->item, true)); + + + if ($editingCategory) { + Log::debug('Updating existing supplier'); + $supplier->update($this->sanitizeItemForUpdating($supplier)); + } else { + Log::debug('Creating supplier'); + $supplier->fill($this->sanitizeItemForStoring($supplier)); + } + + if ($supplier->save()) { + $this->log('Category '.$supplier->name.' created or updated from CSV import'); + return $supplier; + + } else { + Log::debug($supplier->getErrors()); + $this->logError($supplier, 'Category "'.$this->item['name'].'"'); + return $supplier->errors; + } + + + } +} \ No newline at end of file diff --git a/app/Importer/ItemImporter.php b/app/Importer/ItemImporter.php index b13dba25fe..9283e79ab9 100644 --- a/app/Importer/ItemImporter.php +++ b/app/Importer/ItemImporter.php @@ -110,7 +110,7 @@ class ItemImporter extends Importer protected function determineCheckout($row) { // Locations don't get checked out to anyone/anything - if ((get_class($this) == LocationImporter::class) || (get_class($this) == AssetModelImporter::class) || (get_class($this) == SupplierImporter::class) || (get_class($this) == ManufacturerImporter::class)) { + if ((get_class($this) == LocationImporter::class) || (get_class($this) == AssetModelImporter::class) || (get_class($this) == SupplierImporter::class) || (get_class($this) == ManufacturerImporter::class) || (get_class($this) == CategoryImporter::class)) { return; } diff --git a/app/Livewire/Importer.php b/app/Livewire/Importer.php index fcd2ba6d6b..1d006344c8 100644 --- a/app/Livewire/Importer.php +++ b/app/Livewire/Importer.php @@ -42,6 +42,7 @@ class Importer extends Component public $consumables_fields; public $components_fields; public $manufacturers_fields; + public $categories_fields; public $aliases_fields; protected $rules = [ @@ -103,6 +104,9 @@ class Importer extends Component case 'manufacturer': $results = $this->manufacturers_fields; break; + case 'category': + $results = $this->categories_fields; + break; default: $results = []; } @@ -176,6 +180,7 @@ class Importer extends Component 'user' => trans('general.users'), 'supplier' => trans('general.suppliers'), 'manufacturer' => trans('general.manufacturers'), + 'category' => trans('general.categories'), ]; /** @@ -379,6 +384,18 @@ class Importer extends Component 'url' => trans('general.url'), ]; + $this->categories_fields = [ + 'id' => trans('general.id'), + 'name' => trans('general.name'), + 'notes' => trans('general.notes'), + 'category_type' => trans('general.type'), + 'eula_text' => trans('admin/categories/general.eula_text'), +// 'use_default_eula' => trans('admin/categories/general.use_default_eula'), +// 'require_acceptance' => trans('admin/categories/general.require_acceptance'), +// 'checkin_email' => trans('admin/categories/general.checkin_email'), + ]; + + $this->assetmodels_fields = [ 'category' => trans('general.category'), diff --git a/database/factories/ImportFactory.php b/database/factories/ImportFactory.php index 95c9645524..5355cac834 100644 --- a/database/factories/ImportFactory.php +++ b/database/factories/ImportFactory.php @@ -219,4 +219,18 @@ class ImportFactory extends Factory }); } + public function categories() + { + return $this->state(function (array $attributes) { + $fileBuilder = Importing\CategoriesImportFileBuilder::new(); + $attributes['name'] = "Category {$attributes['name']}"; + $attributes['import_type'] = 'category'; + $attributes['header_row'] = $fileBuilder->toCsv()[0]; + $attributes['first_row'] = $fileBuilder->firstRow(); + + return $attributes; + }); + } + + } diff --git a/resources/views/livewire/importer.blade.php b/resources/views/livewire/importer.blade.php index c2514f6809..8756bd4462 100644 --- a/resources/views/livewire/importer.blade.php +++ b/resources/views/livewire/importer.blade.php @@ -191,7 +191,7 @@ - @if (($typeOfImport != 'location' && $typeOfImport!= 'assetModel' && $typeOfImport!= 'component' && $typeOfImport!= 'supplier') && $typeOfImport!= 'manufacturer' && ($typeOfImport!='')) + @if (($typeOfImport != 'location' && $typeOfImport!= 'assetModel' && $typeOfImport!= 'component' && $typeOfImport!= 'supplier') && $typeOfImport!= 'manufacturer' && $typeOfImport!= 'category' && ($typeOfImport!=''))