Skip to content

Commit 3c08760

Browse files
authored
Merge pull request #15802 from snipe/features/import_models
Ability to import asset models (separate from assets)
2 parents ab2e7a3 + 7ccbc60 commit 3c08760

24 files changed

+567
-42
lines changed

app/Http/Controllers/Api/AssetModelsController.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public function index(Request $request) : JsonResponse | array
5959
'model_number',
6060
'min_amt',
6161
'eol',
62+
'created_by',
6263
'requestable',
6364
'models.notes',
6465
'models.created_at',
@@ -69,7 +70,7 @@ public function index(Request $request) : JsonResponse | array
6970
'models.deleted_at',
7071
'models.updated_at',
7172
])
72-
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues','adminuser')
73+
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues', 'adminuser')
7374
->withCount('assets as assets_count');
7475

7576
if ($request->input('status')=='deleted') {
@@ -95,7 +96,7 @@ public function index(Request $request) : JsonResponse | array
9596
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
9697
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'models.created_at';
9798

98-
switch ($sort) {
99+
switch ($request->input('sort')) {
99100
case 'manufacturer':
100101
$assetmodels->OrderManufacturer($order);
101102
break;
@@ -105,6 +106,9 @@ public function index(Request $request) : JsonResponse | array
105106
case 'fieldset':
106107
$assetmodels->OrderFieldset($order);
107108
break;
109+
case 'created_by':
110+
$assetmodels->OrderByCreatedByName($order);
111+
break;
108112
default:
109113
$assetmodels->orderBy($sort, $order);
110114
break;

app/Http/Controllers/Api/ImportController.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ class ImportController extends Controller
2828
public function index() : JsonResponse | array
2929
{
3030
$this->authorize('import');
31-
$imports = Import::latest()->get();
32-
31+
$imports = Import::with('adminuser')->latest()->get();
3332
return (new ImportsTransformer)->transformImports($imports);
3433
}
3534

@@ -133,7 +132,7 @@ public function store() : JsonResponse
133132
}
134133

135134
$import->filesize = filesize($path.'/'.$file_name);
136-
135+
$import->created_by = auth()->id();
137136
$import->save();
138137
$results[] = $import;
139138
}
@@ -177,6 +176,9 @@ public function process(ItemImportRequest $request, $import_id) : JsonResponse
177176
case 'asset':
178177
$redirectTo = 'hardware.index';
179178
break;
179+
case 'assetModel':
180+
$redirectTo = 'models.index';
181+
break;
180182
case 'accessory':
181183
$redirectTo = 'accessories.index';
182184
break;

app/Http/Requests/ItemImportRequest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@ public function import(Import $import)
3838

3939
$filename = config('app.private_uploads').'/imports/'.$import->file_path;
4040
$import->import_type = $this->input('import-type');
41-
$class = title_case($import->import_type);
41+
$class = ucfirst($import->import_type);
4242
$classString = "App\\Importer\\{$class}Importer";
4343
$importer = new $classString($filename);
4444
$import->field_map = request('column-mappings');
45+
$import->created_by = auth()->id();
4546
$import->save();
4647
$fieldMappings = [];
4748

@@ -60,7 +61,7 @@ public function import(Import $import)
6061
$fieldMappings = array_change_key_case(array_flip($import->field_map), CASE_LOWER);
6162
}
6263
$importer->setCallbacks([$this, 'log'], [$this, 'progress'], [$this, 'errorCallback'])
63-
->setUserId(auth()->id())
64+
->setCreatedBy(auth()->id())
6465
->setUpdating($this->get('import-update'))
6566
->setShouldNotify($this->get('send-welcome'))
6667
->setUsernameFormat('firstname.lastname')

app/Http/Transformers/AssetModelsTransformer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ public function transformAssetModel(AssetModel $assetmodel)
6565
'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None',
6666
'requestable' => ($assetmodel->requestable == '1') ? true : false,
6767
'notes' => Helper::parseEscapedMarkedownInline($assetmodel->notes),
68+
'created_by' => ($assetmodel->adminuser) ? [
69+
'id' => (int) $assetmodel->adminuser->id,
70+
'name'=> e($assetmodel->adminuser->present()->fullName()),
71+
] : null,
6872
'created_at' => Helper::getFormattedDateObject($assetmodel->created_at, 'datetime'),
6973
'updated_at' => Helper::getFormattedDateObject($assetmodel->updated_at, 'datetime'),
7074
'deleted_at' => Helper::getFormattedDateObject($assetmodel->deleted_at, 'datetime'),

app/Importer/AccessoryImporter.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public function createAccessoryIfNotExists($row)
4242
}
4343
$this->log('No Matching Accessory, Creating a new one');
4444
$accessory = new Accessory();
45+
$accessory->created_by = auth()->id();
4546
$this->item['model_number'] = $this->findCsvMatch($row, "model_number");
4647
$this->item['min_amt'] = $this->findCsvMatch($row, "min_amt");
4748
$accessory->fill($this->sanitizeItemForStoring($accessory));
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
<?php
2+
3+
namespace App\Importer;
4+
5+
use App\Models\AssetModel;
6+
use App\Models\Depreciation;
7+
use App\Models\CustomFieldset;
8+
use Illuminate\Support\Facades\Log;
9+
10+
/**
11+
* When we are importing users via an Asset/etc import, we use createOrFetchUser() in
12+
* Importer\Importer.php. [ALG]
13+
*
14+
* Class LocationImporter
15+
*/
16+
class AssetModelImporter extends ItemImporter
17+
{
18+
protected $models;
19+
20+
public function __construct($filename)
21+
{
22+
parent::__construct($filename);
23+
}
24+
25+
protected function handle($row)
26+
{
27+
parent::handle($row);
28+
$this->createAssetModelIfNotExists($row);
29+
}
30+
31+
/**
32+
* Create a model if a duplicate does not exist.
33+
* @todo Investigate how this should interact with Importer::createModelIfNotExists
34+
*
35+
* @author A. Gianotto
36+
* @since 6.1.0
37+
* @param array $row
38+
*/
39+
public function createAssetModelIfNotExists(array $row)
40+
{
41+
42+
$editingAssetModel = false;
43+
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
44+
45+
if ($assetModel) {
46+
if (! $this->updating) {
47+
$this->log('A matching Model '.$this->item['name'].' already exists');
48+
return;
49+
}
50+
51+
$this->log('Updating Model');
52+
$editingAssetModel = true;
53+
} else {
54+
$this->log('No Matching Model, Create a new one');
55+
$assetModel = new AssetModel();
56+
}
57+
58+
// Pull the records from the CSV to determine their values
59+
$this->item['name'] = trim($this->findCsvMatch($row, 'name'));
60+
$this->item['category'] = trim($this->findCsvMatch($row, 'category'));
61+
$this->item['manufacturer'] = trim($this->findCsvMatch($row, 'manufacturer'));
62+
$this->item['min_amt'] = trim($this->findCsvMatch($row, 'min_amt'));
63+
$this->item['model_number'] = trim($this->findCsvMatch($row, 'model_number'));
64+
$this->item['eol'] = trim($this->findCsvMatch($row, 'eol'));
65+
$this->item['notes'] = trim($this->findCsvMatch($row, 'notes'));
66+
$this->item['fieldset'] = trim($this->findCsvMatch($row, 'fieldset'));
67+
$this->item['depreciation'] = trim($this->findCsvMatch($row, 'depreciation'));
68+
$this->item['requestable'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'))) == 1) ? 1 : 0;
69+
70+
if (!empty($this->item['category'])) {
71+
if ($category = $this->createOrFetchCategory($this->item['category'])) {
72+
$this->item['category_id'] = $category;
73+
}
74+
}
75+
if (!empty($this->item['manufacturer'])) {
76+
if ($manufacturer = $this->createOrFetchManufacturer($this->item['manufacturer'])) {
77+
$this->item['manufacturer_id'] = $manufacturer;
78+
}
79+
}
80+
81+
if (!empty($this->item['depreciation'])) {
82+
if ($depreciation = $this->fetchDepreciation($this->item['depreciation'])) {
83+
$this->item['depreciation_id'] = $depreciation;
84+
}
85+
}
86+
87+
if (!empty($this->item['fieldset'])) {
88+
if ($fieldset = $this->createOrFetchCustomFieldset($this->item['fieldset'])) {
89+
$this->item['fieldset_id'] = $fieldset;
90+
}
91+
}
92+
93+
Log::debug('Item array is: ');
94+
Log::debug(print_r($this->item, true));
95+
96+
97+
if ($editingAssetModel) {
98+
Log::debug('Updating existing model');
99+
$assetModel->update($this->sanitizeItemForUpdating($assetModel));
100+
} else {
101+
Log::debug('Creating model');
102+
$assetModel->fill($this->sanitizeItemForStoring($assetModel));
103+
$assetModel->created_by = auth()->id();
104+
}
105+
106+
if ($assetModel->save()) {
107+
$this->log('AssetModel '.$assetModel->name.' created or updated from CSV import');
108+
return $assetModel;
109+
110+
} else {
111+
$this->log($assetModel->getErrors()->first());
112+
$this->addErrorToBag($assetModel, $assetModel->getErrors()->keys()[0], $assetModel->getErrors()->first());
113+
return $assetModel->getErrors();
114+
}
115+
116+
}
117+
118+
119+
/**
120+
* Fetch an existing depreciation, or create new if it doesn't exist.
121+
*
122+
* We only do a fetch vs create here since Depreciations have additional fields required
123+
* and cannot be created without them (months, for example.))
124+
*
125+
* @author A. Gianotto
126+
* @since 7.1.3
127+
* @param $depreciation_name string
128+
* @return int id of depreciation created/found
129+
*/
130+
public function fetchDepreciation($depreciation_name) : ?int
131+
{
132+
if ($depreciation_name != '') {
133+
134+
if ($depreciation = Depreciation::where('name', '=', $depreciation_name)->first()) {
135+
$this->log('A matching Depreciation '.$depreciation_name.' already exists');
136+
return $depreciation->id;
137+
}
138+
}
139+
140+
return null;
141+
}
142+
143+
/**
144+
* Fetch an existing fieldset, or create new if it doesn't exist
145+
*
146+
* @author A. Gianotto
147+
* @since 7.1.3
148+
* @param $fieldset_name string
149+
* @return int id of fieldset created/found
150+
*/
151+
public function createOrFetchCustomFieldset($fieldset_name) : ?int
152+
{
153+
if ($fieldset_name != '') {
154+
$fieldset = CustomFieldset::where('name', '=', $fieldset_name)->first();
155+
156+
if ($fieldset) {
157+
$this->log('A matching fieldset '.$fieldset_name.' already exists');
158+
return $fieldset->id;
159+
}
160+
161+
$fieldset = new CustomFieldset();
162+
$fieldset->name = $fieldset_name;
163+
164+
if ($fieldset->save()) {
165+
$this->log('Fieldset '.$fieldset_name.' was created');
166+
167+
return $fieldset->id;
168+
}
169+
$this->logError($fieldset, 'Fieldset');
170+
}
171+
172+
return null;
173+
}
174+
}

app/Importer/ComponentImporter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function createComponentIfNotExists()
4747
}
4848
$this->log('No matching component, creating one');
4949
$component = new Component;
50+
$component->created_by = auth()->id();
5051
$component->fill($this->sanitizeItemForStoring($component));
5152

5253
// This sets an attribute on the Loggable trait for the action log
@@ -58,7 +59,7 @@ public function createComponentIfNotExists()
5859
if (isset($this->item['asset_tag']) && ($asset = Asset::where('asset_tag', $this->item['asset_tag'])->first())) {
5960
$component->assets()->attach($component->id, [
6061
'component_id' => $component->id,
61-
'created_by' => $this->created_by,
62+
'created_by' => auth()->id(),
6263
'created_at' => date('Y-m-d H:i:s'),
6364
'assigned_qty' => 1, // Only assign the first one to the asset
6465
'asset_id' => $asset->id,

app/Importer/ConsumableImporter.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public function createConsumableIfNotExists($row)
4141
}
4242
$this->log('No matching consumable, creating one');
4343
$consumable = new Consumable();
44+
$consumable->created_by = auth()->id();
4445
$this->item['model_number'] = trim($this->findCsvMatch($row, 'model_number'));
4546
$this->item['item_no'] = trim($this->findCsvMatch($row, 'item_number'));
4647
$this->item['min_amt'] = trim($this->findCsvMatch($row, "min_amt"));

app/Importer/Importer.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ protected function createOrFetchUser($row, $type = 'user')
363363

364364
// No luck finding a user on username or first name, let's create one.
365365
$user = new User;
366+
366367
$user->first_name = $user_array['first_name'];
367368
$user->last_name = $user_array['last_name'];
368369
$user->username = $user_array['username'];
@@ -406,7 +407,7 @@ protected function findUserByNumber($user_name)
406407
*
407408
* @return self
408409
*/
409-
public function setUserId($created_by)
410+
public function setCreatedBy($created_by)
410411
{
411412
$this->created_by = $created_by;
412413

@@ -492,6 +493,16 @@ public function setUsernameFormat($usernameFormat)
492493

493494
public function fetchHumanBoolean($value)
494495
{
496+
$true = [
497+
'yes',
498+
'y',
499+
'true',
500+
];
501+
502+
if (in_array(strtolower($value), $true)) {
503+
return 1;
504+
}
505+
495506
return (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
496507
}
497508

@@ -528,6 +539,7 @@ public function createOrFetchDepartment($user_department_name)
528539
return null;
529540
}
530541

542+
531543
/**
532544
* Fetch an existing manager
533545
*

0 commit comments

Comments
 (0)