'required|string', 'files.*.created_at' => 'required|string', 'files.*.filesize' => 'required|integer', 'headerRow' => 'array', 'typeOfImport' => 'string', 'field_map' => 'array' ]; /** * This is used in resources/views/livewire.importer.blade.php, and we kinda shouldn't need to check for * activeFile here, but there's some UI goofiness that allows this to crash out on some imports. * * @return string */ public function generate_field_map() { $tmp = array(); if ($this->activeFile) { $tmp = array_combine($this->headerRow, $this->field_map); $tmp = array_filter($tmp); } return json_encode($tmp); } private function getColumns($type) { switch ($type) { case 'asset': $results = $this->assets_fields; break; case 'assetmodel': $results = $this->assetmodels_fields; break; case 'accessory': $results = $this->accessories_fields; break; case 'component': $results = $this->components_fields; break; case 'consumable': $results = $this->consumables_fields; break; case 'license': $results = $this->licenses_fields; break; case 'location': $results = $this->locations_fields; break; case 'user': $results = $this->users_fields; break; default: $results = []; } asort($results, SORT_FLAG_CASE | SORT_STRING); if ($type == "asset") { // add Custom Fields after a horizontal line $results['-'] = "———" . trans('admin/custom_fields/general.custom_fields') . "———’"; foreach (CustomField::orderBy('name')->get() as $field) { $results[$field->db_column_name()] = $field->name; } } return $results; } public function updatingTypeOfImport($type) { // go through each header, find a matching field to try and map it to. foreach ($this->headerRow as $i => $header) { // do we have something mapped already? if (array_key_exists($i, $this->field_map)) { // yes, we do. Is it valid for this type of import? // (e.g. the import type might have been changed...?) if (array_key_exists($this->field_map[$i], $this->columnOptions[$type])) { //yes, this key *is* valid. Continue on to the next field. continue; } else { //no, this key is *INVALID* for this import type. Better set it to null // and we'll hope that the $aliases_fields or something else picks it up. $this->field_map[$i] = null; // fingers crossed! But it's not likely, tbh. } // TODO - strictly speaking, this isn't necessary here I don't think. } // first, check for exact matches foreach ($this->columnOptions[$type] as $v => $text) { if (strcasecmp($text, $header) === 0) { // case-INSENSITIVe on purpose! $this->field_map[$i] = $v; continue 2; //don't bother with the alias check, go to the next header } } // if you got here, we didn't find a match. Try the $aliases_fields foreach ($this->aliases_fields as $key => $alias_values) { foreach ($alias_values as $alias_value) { if (strcasecmp($alias_value, $header) === 0) { // aLsO CaSe-INSENSitiVE! // Make *absolutely* sure that this key actually _exists_ in this import type - // you can trigger this by importing accessories with a 'Warranty' column (which don't exist // in "Accessories"!) if (array_key_exists($key, $this->columnOptions[$type])) { $this->field_map[$i] = $key; continue 3; // bust out of both of these loops; as well as the surrounding one - e.g. move on to the next header } } } } // and if you got here, we got nothing. Let's recommend 'null' $this->field_map[$i] = null; // Booooo :( } } public function mount() { $this->authorize('import'); $this->importTypes = [ 'accessory' => trans('general.accessories'), 'asset' => trans('general.assets'), 'assetmodel' => trans('general.asset_models'), 'component' => trans('general.components'), 'consumable' => trans('general.consumables'), 'license' => trans('general.licenses'), 'location' => trans('general.locations'), 'user' => trans('general.users'), ]; /** * These are the item-type specific columns */ $this->accessories_fields = [ 'company' => trans('general.company'), 'location' => trans('general.location'), 'quantity' => trans('general.qty'), 'item_name' => trans('general.item_name_var', ['item' => trans('general.accessory')]), 'model_number' => trans('general.model_no'), 'notes' => trans('general.notes'), 'category' => trans('general.category'), 'supplier' => trans('general.supplier'), 'min_amt' => trans('mail.min_QTY'), 'purchase_cost' => trans('general.purchase_cost'), 'purchase_date' => trans('general.purchase_date'), 'manufacturer' => trans('general.manufacturer'), 'order_number' => trans('general.order_number'), ]; $this->assets_fields = [ 'company' => trans('general.company'), 'location' => trans('general.location'), 'item_name' => trans('general.item_name_var', ['item' => trans('general.asset')]), 'asset_tag' => trans('general.asset_tag'), 'asset_model' => trans('general.model_name'), 'byod' => trans('general.byod'), 'model_number' => trans('general.model_no'), 'status' => trans('general.status'), 'warranty_months' => trans('admin/hardware/form.warranty'), 'category' => trans('general.category'), 'requestable' => trans('admin/hardware/general.requestable'), 'serial' => trans('general.serial_number'), 'supplier' => trans('general.supplier'), 'purchase_cost' => trans('general.purchase_cost'), 'purchase_date' => trans('general.purchase_date'), 'asset_notes' => trans('general.item_notes', ['item' => trans('admin/hardware/general.asset')]), 'model_notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]), 'manufacturer' => trans('general.manufacturer'), 'order_number' => trans('general.order_number'), 'image' => trans('general.importer.image_filename'), 'asset_eol_date' => trans('admin/hardware/form.eol_date'), /** * Checkout fields: * Assets can be checked out to other assets, people, or locations, but we currently * only support checkout to people and locations in the importer **/ 'checkout_class' => trans('general.importer.checkout_type'), 'first_name' => trans('general.importer.checked_out_to_first_name'), 'last_name' => trans('general.importer.checked_out_to_last_name'), 'full_name' => trans('general.importer.checked_out_to_fullname'), 'email' => trans('general.importer.checked_out_to_email'), 'username' => trans('general.importer.checked_out_to_username'), 'checkout_location' => trans('general.importer.checkout_location'), /** * These are here so users can import history, to replace the dinosaur that * was the history importer */ 'last_checkin' => trans('admin/hardware/table.last_checkin_date'), 'last_checkout' => trans('admin/hardware/table.checkout_date'), 'expected_checkin' => trans('admin/hardware/form.expected_checkin'), 'last_audit_date' => trans('general.last_audit'), 'next_audit_date' => trans('general.next_audit_date'), ]; $this->consumables_fields = [ 'company' => trans('general.company'), 'location' => trans('general.location'), 'quantity' => trans('general.qty'), 'item_name' => trans('general.item_name_var', ['item' => trans('general.consumable')]), 'model_number' => trans('general.model_no'), 'notes' => trans('general.notes'), 'min_amt' => trans('mail.min_QTY'), 'category' => trans('general.category'), 'purchase_cost' => trans('general.purchase_cost'), 'purchase_date' => trans('general.purchase_date'), 'checkout_class' => trans('general.importer.checkout_type'), 'supplier' => trans('general.supplier'), 'manufacturer' => trans('general.manufacturer'), 'order_number' => trans('general.order_number'), 'item_no' => trans('admin/consumables/general.item_no'), ]; $this->components_fields = [ 'company' => trans('general.company'), 'location' => trans('general.location'), 'quantity' => trans('general.qty'), 'item_name' => trans('general.item_name_var', ['item' => trans('general.component')]), 'model_number' => trans('general.model_no'), 'notes' => trans('general.notes'), 'category' => trans('general.category'), 'supplier' => trans('general.supplier'), 'min_amt' => trans('mail.min_QTY'), 'purchase_cost' => trans('general.purchase_cost'), 'purchase_date' => trans('general.purchase_date'), 'manufacturer' => trans('general.manufacturer'), 'order_number' => trans('general.order_number'), 'serial' => trans('general.serial_number'), ]; $this->licenses_fields = [ 'company' => trans('general.company'), 'location' => trans('general.location'), 'item_name' => trans('general.item_name_var', ['item' => trans('general.license')]), 'asset_tag' => trans('general.importer.checked_out_to_tag'), 'expiration_date' => trans('admin/licenses/form.expiration'), 'full_name' => trans('general.importer.checked_out_to_fullname'), 'license_email' => trans('admin/licenses/form.to_email'), 'license_name' => trans('admin/licenses/form.to_name'), 'purchase_order' => trans('admin/licenses/form.purchase_order'), 'order_number' => trans('general.order_number'), 'reassignable' => trans('admin/licenses/form.reassignable'), 'seats' => trans('admin/licenses/form.seats'), 'notes' => trans('general.notes'), 'category' => trans('general.category'), 'supplier' => trans('general.supplier'), 'purchase_cost' => trans('general.purchase_cost'), 'purchase_date' => trans('general.purchase_date'), 'maintained' => trans('admin/licenses/form.maintained'), 'checkout_class' => trans('general.importer.checkout_type'), 'serial' => trans('general.license_serial'), 'email' => trans('general.importer.checked_out_to_email'), 'username' => trans('general.importer.checked_out_to_username'), 'manufacturer' => trans('general.manufacturer'), ]; $this->users_fields = [ 'id' => trans('general.id'), 'company' => trans('general.company'), 'location' => trans('general.location'), 'department' => trans('general.department'), 'first_name' => trans('general.first_name'), 'last_name' => trans('general.last_name'), 'notes' => trans('general.notes'), 'username' => trans('admin/users/table.username'), 'jobtitle' => trans('admin/users/table.title'), 'phone_number' => trans('admin/users/table.phone'), 'manager_first_name' => trans('general.importer.manager_first_name'), 'manager_last_name' => trans('general.importer.manager_last_name'), 'activated' => trans('general.activated'), 'address' => trans('general.address'), 'city' => trans('general.city'), 'state' => trans('general.state'), 'country' => trans('general.country'), 'zip' => trans('general.zip'), 'vip' => trans('general.importer.vip'), 'remote' => trans('admin/users/general.remote'), 'email' => trans('admin/users/table.email'), 'website' => trans('general.website'), 'avatar' => trans('general.image'), 'gravatar' => trans('general.importer.gravatar'), 'start_date' => trans('general.start_date'), 'end_date' => trans('general.end_date'), 'employee_num' => trans('general.employee_number'), ]; $this->locations_fields = [ 'name' => trans('general.item_name_var', ['item' => trans('general.location')]), 'address' => trans('general.address'), 'address2' => trans('general.importer.address2'), 'city' => trans('general.city'), 'state' => trans('general.state'), 'country' => trans('general.country'), 'zip' => trans('general.zip'), 'currency' => trans('general.importer.currency'), 'ldap_ou' => trans('admin/locations/table.ldap_ou'), 'manager_username' => trans('general.importer.manager_username'), 'manager' => trans('general.importer.manager_full_name'), 'parent_location' => trans('admin/locations/table.parent'), ]; $this->assetmodels_fields = [ 'item_name' => trans('general.item_name_var', ['item' => trans('general.asset_model')]), 'category' => trans('general.category'), 'manufacturer' => trans('general.manufacturer'), 'model_number' => trans('general.model_no'), 'notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]), 'min_amt' => trans('mail.min_QTY'), 'fieldset' => trans('admin/models/general.fieldset'), 'eol' => trans('general.eol'), 'requestable' => trans('admin/models/general.requestable'), ]; // "real fieldnames" to a list of aliases for that field $this->aliases_fields = [ 'item_name' => [ 'item name', 'asset name', 'accessory name', 'user name', 'consumable name', 'component name', 'name', ], 'item_no' => [ 'item number', 'item no.', 'item #', ], 'asset_model' => [ 'model name', 'model', ], 'eol_date' => [ 'eol', 'eol date', 'asset eol date', ], 'eol' => [ 'eol', 'EOL', 'eol months', ], 'depreciation' => [ 'Depreciation', 'depreciation', ], 'requestable' => [ 'requestable', 'Requestable', ], 'gravatar' => [ 'gravatar', ], 'currency' => [ '$', ], 'jobtitle' => [ 'job title for user', 'job title', ], 'full_name' => [ 'full name', 'fullname', trans('general.importer.checked_out_to_fullname') ], 'username' => [ 'user name', 'username', trans('general.importer.checked_out_to_username'), ], 'first_name' => [ 'first name', trans('general.importer.checked_out_to_first_name'), ], 'last_name' => [ 'last name', 'lastname', trans('general.importer.checked_out_to_last_name'), ], 'email' => [ 'email', 'e-mail', trans('general.importer.checked_out_to_email'), ], 'phone_number' => [ 'phone', 'phone number', 'phone num', 'telephone number', 'telephone', 'tel.', ], 'serial' => [ 'serial number', 'serial no.', 'serial no', 'product key', 'key', ], 'model_number' => [ 'model', 'model no', 'model no.', 'model number', 'model num', 'model num.' ], 'warranty_months' => [ 'Warranty', 'Warranty Months' ], 'qty' => [ 'QTY', 'Quantity' ], 'zip' => [ 'Postal Code', 'Post Code', 'Zip Code' ], 'min_amt' => [ 'Min Amount', 'Minimum Amount', 'Min Quantity', 'Minimum Quantity', ], 'next_audit_date' => [ 'Next Audit', ], 'last_checkout' => [ 'Last Checkout', 'Last Checkout Date', 'Checkout Date', ], 'address2' => [ 'Address 2', 'Address2', ], 'ldap_ou' => [ 'LDAP OU', 'OU', ], 'parent_location' => [ 'Parent', 'Parent Location', ], 'manager' => [ 'Managed By', 'Manager Name', 'Manager Full Name', ], 'manager_username' => [ 'Manager Username', ], ]; $this->columnOptions[''] = $this->getColumns(''); //blank mode? I don't know what this is supposed to mean foreach ($this->importTypes as $type => $name) { $this->columnOptions[$type] = $this->getColumns($type); } if ($this->activeFile) { $this->field_map = $this->activeFile->field_map ? array_values($this->activeFile->field_map) : []; } } public function selectFile($id) { $this->clearMessage(); $this->activeFileId = $id; if (!$this->activeFile) { $this->message = trans('admin/hardware/message.import.file_missing'); $this->message_type = 'danger'; return; } $this->headerRow = $this->activeFile->header_row; $this->typeOfImport = $this->activeFile->import_type; $this->field_map = null; foreach ($this->headerRow as $element) { if (isset($this->activeFile->field_map[$element])) { $this->field_map[] = $this->activeFile->field_map[$element]; } else { $this->field_map[] = null; // re-inject the 'nulls' if a file was imported with some 'Do Not Import' settings } } $this->file_id = $id; $this->import_errors = null; $this->statusText = null; } public function destroy($id) { $this->authorize('import'); $import = Import::find($id); // Check that the import wasn't deleted after while page was already loaded... // @todo: next up...handle the file being missing for other interactions... // for example having an import open in two tabs, deleting it, and then changing // the import type in the other tab. The error message below wouldn't display in that case. if (!$import) { $this->message = trans('admin/hardware/message.import.file_already_deleted'); $this->message_type = 'danger'; return; } if (Storage::delete('private_uploads/imports/' . $import->file_path)) { $import->delete(); $this->message = trans('admin/hardware/message.import.file_delete_success'); $this->message_type = 'success'; unset($this->files); return; } $this->message = trans('admin/hardware/message.import.file_delete_error'); $this->message_type = 'danger'; } public function clearMessage() { $this->message = null; $this->message_type = null; } #[Computed] public function files() { return Import::orderBy('id', 'desc')->get(); } #[Computed] public function activeFile() { return Import::find($this->activeFileId); } public function render() { return view('livewire.importer') ->extends('layouts.default') ->section('content'); } }