mirror of
https://github.com/snipe/snipe-it.git
synced 2024-11-09 23:24:06 -08:00
Merge pull request #12846 from snipe/features/livewire_location_import
Location importer via Livewire Importer
This commit is contained in:
commit
ea17fdeba5
|
@ -193,6 +193,9 @@ class ImportController extends Controller
|
|||
case 'user':
|
||||
$redirectTo = 'users.index';
|
||||
break;
|
||||
case 'location':
|
||||
$redirectTo = 'locations.index';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($errors) { //Failure
|
||||
|
|
|
@ -116,8 +116,8 @@ class Importer extends Component
|
|||
static $users = [
|
||||
'employee_num' => 'Employee Number',
|
||||
'first_name' => 'First Name',
|
||||
'jobtitle' => 'Job Title',
|
||||
'last_name' => 'Last Name',
|
||||
'jobtitle' => 'Job Title',
|
||||
'phone_number' => 'Phone Number',
|
||||
'manager_first_name' => 'Manager First Name',
|
||||
'manager_last_name' => 'Manager Last Name',
|
||||
|
@ -126,7 +126,24 @@ class Importer extends Component
|
|||
'city' => 'City',
|
||||
'state' => 'State',
|
||||
'country' => 'Country',
|
||||
'vip' => 'VIP'
|
||||
'zip' => 'Zip',
|
||||
'vip' => 'VIP',
|
||||
'remote' => 'Remote',
|
||||
];
|
||||
|
||||
static $locations = [
|
||||
'name' => 'Name',
|
||||
'address' => 'Address',
|
||||
'address2' => 'Address 2',
|
||||
'city' => 'City',
|
||||
'state' => 'State',
|
||||
'country' => 'Country',
|
||||
'zip' => 'Zip',
|
||||
'currency' => 'Currency',
|
||||
'ldap_ou' => 'LDAP OU',
|
||||
'manager_username' => 'Manager Username',
|
||||
'manager' => 'Manager',
|
||||
'parent_location' => 'Parent Location',
|
||||
];
|
||||
|
||||
//array of "real fieldnames" to a list of aliases for that field
|
||||
|
@ -150,6 +167,11 @@ class Importer extends Component
|
|||
'QTY',
|
||||
'Quantity'
|
||||
],
|
||||
'zip' =>
|
||||
[
|
||||
'Postal Code',
|
||||
'Post Code'
|
||||
],
|
||||
'min_amt' =>
|
||||
[
|
||||
'Min Amount',
|
||||
|
@ -159,6 +181,31 @@ class Importer extends Component
|
|||
[
|
||||
'Next Audit',
|
||||
],
|
||||
'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',
|
||||
],
|
||||
|
||||
|
||||
];
|
||||
|
@ -181,6 +228,9 @@ class Importer extends Component
|
|||
case 'user':
|
||||
$results = self::$general + self::$users;
|
||||
break;
|
||||
case 'location':
|
||||
$results = self::$general + self::$locations;
|
||||
break;
|
||||
default:
|
||||
$results = self::$general;
|
||||
}
|
||||
|
@ -252,7 +302,6 @@ class Importer extends Component
|
|||
$this->authorize('import');
|
||||
$this->progress = -1; // '-1' means 'don't show the progressbar'
|
||||
$this->progress_bar_class = 'progress-bar-warning';
|
||||
\Log::debug("Hey, we are calling MOUNT (in the importer-file) !!!!!!!!"); //fcuk
|
||||
$this->importTypes = [
|
||||
'asset' => trans('general.assets'),
|
||||
'accessory' => trans('general.accessories'),
|
||||
|
@ -260,6 +309,7 @@ class Importer extends Component
|
|||
'component' => trans('general.components'),
|
||||
'license' => trans('general.licenses'),
|
||||
'user' => trans('general.users'),
|
||||
'location' => trans('general.locations'),
|
||||
];
|
||||
|
||||
$this->columnOptions[''] = $this->getColumns(''); //blank mode? I don't know what this is supposed to mean
|
||||
|
@ -273,8 +323,7 @@ class Importer extends Component
|
|||
|
||||
public function selectFile($id)
|
||||
{
|
||||
\Log::debug("TOGGLE EVENT FIRED!");
|
||||
\Log::debug("The ID we are trying to find is AS FOLLOWS: ".$id);
|
||||
|
||||
$this->activeFile = Import::find($id);
|
||||
$this->field_map = null;
|
||||
foreach($this->activeFile->header_row as $element) {
|
||||
|
@ -284,11 +333,9 @@ class Importer extends Component
|
|||
$this->field_map[] = null; // re-inject the 'nulls' if a file was imported with some 'Do Not Import' settings
|
||||
}
|
||||
}
|
||||
//$this->field_map = $this->activeFile->field_map ? array_values($this->activeFile->field_map) : []; // this is wrong
|
||||
$this->file_id = $id;
|
||||
$this->import_errors = null;
|
||||
$this->statusText = null;
|
||||
\Log::debug("The import type we are about to try and load up is gonna be this: ".$this->activeFile->import_type);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -65,19 +65,22 @@ abstract class Importer
|
|||
'email' => 'email',
|
||||
'username' => 'username',
|
||||
'address' => 'address',
|
||||
'address2' => 'address2',
|
||||
'city' => 'city',
|
||||
'state' => 'state',
|
||||
'country' => 'country',
|
||||
'zip' => 'zip',
|
||||
'jobtitle' => 'job title',
|
||||
'employee_num' => 'employee number',
|
||||
'phone_number' => 'phone number',
|
||||
'first_name' => 'first name',
|
||||
'last_name' => 'last name',
|
||||
'department' => 'department',
|
||||
'manager_first_name' => 'manager first name',
|
||||
'manager_last_name' => 'manager last name',
|
||||
'manager_name' => 'manager full name',
|
||||
'manager_username' => 'manager username',
|
||||
'min_amt' => 'minimum quantity',
|
||||
'remote' => 'remote',
|
||||
'vip' => 'vip',
|
||||
];
|
||||
/**
|
||||
* Map of item fields->csv names
|
||||
|
@ -119,7 +122,7 @@ abstract class Importer
|
|||
} else {
|
||||
$this->csv = Reader::createFromString($file);
|
||||
}
|
||||
$this->tempPassword = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 20);
|
||||
$this->tempPassword = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 40);
|
||||
}
|
||||
|
||||
// Cached Values for import lookups
|
||||
|
@ -198,11 +201,11 @@ abstract class Importer
|
|||
$val = $default;
|
||||
$key = $this->lookupCustomKey($key);
|
||||
|
||||
$this->log("Custom Key: ${key}");
|
||||
// $this->log("Custom Key: ${key}");
|
||||
if (array_key_exists($key, $array)) {
|
||||
$val = Encoding::toUTF8(trim($array[$key]));
|
||||
}
|
||||
$this->log("${key}: ${val}");
|
||||
//$this->log("${key}: ${val}");
|
||||
return $val;
|
||||
}
|
||||
|
||||
|
@ -280,8 +283,9 @@ abstract class Importer
|
|||
* @return User Model w/ matching name
|
||||
* @internal param array $user_array User details parsed from csv
|
||||
*/
|
||||
protected function createOrFetchUser($row)
|
||||
protected function createOrFetchUser($row, $type = 'user')
|
||||
{
|
||||
|
||||
$user_array = [
|
||||
'full_name' => $this->findCsvMatch($row, 'full_name'),
|
||||
'email' => $this->findCsvMatch($row, 'email'),
|
||||
|
@ -292,31 +296,36 @@ abstract class Importer
|
|||
'remote' => $this->fetchHumanBoolean(($this->findCsvMatch($row, 'remote'))),
|
||||
];
|
||||
|
||||
// Maybe we're lucky and the user already exists.
|
||||
if ($user = User::where('username', $user_array['username'])->first()) {
|
||||
$this->log('User '.$user_array['username'].' already exists');
|
||||
|
||||
return $user;
|
||||
if ($type == 'manager') {
|
||||
$user_array['full_name'] = $this->findCsvMatch($row, 'manager');
|
||||
$user_array['username'] = $this->findCsvMatch($row, 'manager_username');
|
||||
}
|
||||
|
||||
// If the full name is empty, bail out--we need this to extract first name (at the very least)
|
||||
if (empty($user_array['full_name'])) {
|
||||
$this->log('Insufficient user data provided (Full name is required)- skipping user creation, just adding asset');
|
||||
// Maybe we're lucky and the username was passed and it already exists.
|
||||
if (!empty($user_array['username'])) {
|
||||
if ($user = User::where('username', $user_array['username'])->first()) {
|
||||
$this->log('User '.$user_array['username'].' already exists');
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If the full name and username is empty, bail out--we need this to extract first name (at the very least)
|
||||
if ((empty($user_array['username'])) && (empty($user_array['full_name']))) {
|
||||
$this->log('Insufficient user data provided (Full name or username is required) - skipping user creation.');
|
||||
\Log::debug(print_r($user_array, true));
|
||||
\Log::debug(print_r($row, true));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is the user actually an ID?
|
||||
if ($user = $this->findUserByNumber($user_array['full_name'])) {
|
||||
return $user;
|
||||
}
|
||||
$this->log('User does not appear to be an id with number: '.$user_array['full_name'].'. Continuing through our processes');
|
||||
|
||||
// Populate email if it does not exist.
|
||||
if (empty($user_array['email'])) {
|
||||
$user_array['email'] = User::generateEmailFromFullName($user_array['full_name']);
|
||||
}
|
||||
|
||||
// Get some fields for first name and last name based off of full name
|
||||
$user_formatted_array = User::generateFormattedNameFromFullName($user_array['full_name'], Setting::getSettings()->username_format);
|
||||
$user_array['first_name'] = $user_formatted_array['first_name'];
|
||||
$user_array['last_name'] = $user_formatted_array['last_name'];
|
||||
|
@ -326,14 +335,12 @@ abstract class Importer
|
|||
if ($this->usernameFormat == 'email') {
|
||||
$user_array['username'] = $user_array['email'];
|
||||
}
|
||||
}
|
||||
|
||||
// Does this ever actually fire??
|
||||
// Check for a matching user after trying to guess username.
|
||||
if ($user = User::where('username', $user_array['username'])->first()) {
|
||||
$this->log('User '.$user_array['username'].' already exists');
|
||||
|
||||
return $user;
|
||||
// Check for a matching username one more time after trying to guess username.
|
||||
if ($user = User::where('username', $user_array['username'])->first()) {
|
||||
$this->log('User '.$user_array['username'].' already exists');
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
// If at this point we have not found a username or first name, bail out in shame.
|
||||
|
@ -341,7 +348,7 @@ abstract class Importer
|
|||
return false;
|
||||
}
|
||||
|
||||
// No Luck, let's create one.
|
||||
// No luck finding a user on username or first name, let's create one.
|
||||
$user = new User;
|
||||
$user->first_name = $user_array['first_name'];
|
||||
$user->last_name = $user_array['last_name'];
|
||||
|
@ -356,9 +363,9 @@ abstract class Importer
|
|||
|
||||
if ($user->save()) {
|
||||
$this->log('User '.$user_array['username'].' created');
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
$this->logError($user, 'User "'.$user_array['username'].'" was not able to be created.');
|
||||
|
||||
return false;
|
||||
|
|
|
@ -60,8 +60,8 @@ class ItemImporter extends Importer
|
|||
$this->item['department_id'] = $this->createOrFetchDepartment($item_department);
|
||||
}
|
||||
|
||||
$item_manager_first_name = $this->findCsvMatch($row, 'manage_first_name');
|
||||
$item_manager_last_name = $this->findCsvMatch($row, 'manage_last_name');
|
||||
$item_manager_first_name = $this->findCsvMatch($row, 'manager_first_name');
|
||||
$item_manager_last_name = $this->findCsvMatch($row, 'manager_last_name');
|
||||
|
||||
if ($this->shouldUpdateField($item_manager_first_name)) {
|
||||
$this->item['manager_id'] = $this->fetchManager($item_manager_first_name, $item_manager_last_name);
|
||||
|
@ -112,6 +112,10 @@ class ItemImporter extends Importer
|
|||
return $this->createOrFetchUser($row);
|
||||
}
|
||||
|
||||
if (get_class($this) != LocationImporter::class) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strtolower($this->item['checkout_class']) === 'location' && $this->findCsvMatch($row, 'checkout_location') != null ) {
|
||||
return Location::findOrFail($this->createOrFetchLocation($this->findCsvMatch($row, 'checkout_location')));
|
||||
}
|
||||
|
|
102
app/Importer/LocationImporter.php
Normal file
102
app/Importer/LocationImporter.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Location;
|
||||
|
||||
/**
|
||||
* When we are importing users via an Asset/etc import, we use createOrFetchUser() in
|
||||
* Importer\Importer.php. [ALG]
|
||||
*
|
||||
* Class LocationImporter
|
||||
*/
|
||||
class LocationImporter extends ItemImporter
|
||||
{
|
||||
protected $locations;
|
||||
|
||||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
{
|
||||
parent::handle($row);
|
||||
$this->createLocationIfNotExists($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a location if a duplicate does not exist.
|
||||
* @todo Investigate how this should interact with Importer::createLocationIfNotExists
|
||||
*
|
||||
* @author A. Gianotto
|
||||
* @since 6.1.0
|
||||
* @param array $row
|
||||
*/
|
||||
public function createLocationIfNotExists(array $row)
|
||||
{
|
||||
|
||||
$editingLocation = false;
|
||||
$location = Location::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||
|
||||
if ($location) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching Location '.$this->item['name'].' already exists');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log('Updating Location');
|
||||
$editingLocation = true;
|
||||
} else {
|
||||
$this->log('No Matching Location, Create a new one');
|
||||
$location = new Location;
|
||||
}
|
||||
|
||||
// Pull the records from the CSV to determine their values
|
||||
$this->item['name'] = $this->findCsvMatch($row, 'name');
|
||||
$this->item['address'] = $this->findCsvMatch($row, 'address');
|
||||
$this->item['address2'] = $this->findCsvMatch($row, 'address2');
|
||||
$this->item['city'] = $this->findCsvMatch($row, 'city');
|
||||
$this->item['state'] = $this->findCsvMatch($row, 'state');
|
||||
$this->item['country'] = $this->findCsvMatch($row, 'country');
|
||||
$this->item['zip'] = $this->findCsvMatch($row, 'zip');
|
||||
$this->item['currency'] = $this->findCsvMatch($row, 'currency');
|
||||
$this->item['ldap_ou'] = $this->findCsvMatch($row, 'ldap_ou');
|
||||
$this->item['manager'] = $this->findCsvMatch($row, 'manager');
|
||||
$this->item['manager_username'] = $this->findCsvMatch($row, 'manager_username');
|
||||
$this->item['user_id'] = \Auth::user()->id;
|
||||
|
||||
if ($this->findCsvMatch($row, 'parent_location')) {
|
||||
$this->item['parent_id'] = $this->createOrFetchLocation($this->findCsvMatch($row, 'parent_location'));
|
||||
}
|
||||
|
||||
if (!empty($this->item['manager'])) {
|
||||
if ($manager = $this->createOrFetchUser($row, 'manager')) {
|
||||
$this->item['manager_id'] = $manager->id;
|
||||
}
|
||||
}
|
||||
|
||||
\Log::debug('Item array is: ');
|
||||
\Log::debug(print_r($this->item, true));
|
||||
|
||||
|
||||
if ($editingLocation) {
|
||||
\Log::debug('Updating existing location');
|
||||
$location->update($this->sanitizeItemForUpdating($location));
|
||||
} else {
|
||||
\Log::debug('Creating location');
|
||||
$location->fill($this->sanitizeItemForStoring($location));
|
||||
}
|
||||
|
||||
if ($location->save()) {
|
||||
$this->log('Location '.$location->name.' created or updated from CSV import');
|
||||
return $location;
|
||||
|
||||
} else {
|
||||
\Log::debug($location->getErrors());
|
||||
return $location->errors;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ class Location extends SnipeModel
|
|||
'country' => 'min:2|max:255|nullable',
|
||||
'address' => 'max:80|nullable',
|
||||
'address2' => 'max:80|nullable',
|
||||
'zip' => 'min:3|max:10|nullable',
|
||||
'zip' => 'min:3|max:12|nullable',
|
||||
'manager_id' => 'exists:users,id|nullable',
|
||||
'parent_id' => 'non_circular:locations,id',
|
||||
];
|
||||
|
|
20
sample_csvs/MOCK_LOCATIONS.csv
Normal file
20
sample_csvs/MOCK_LOCATIONS.csv
Normal file
|
@ -0,0 +1,20 @@
|
|||
name,address,address2,city,state,country,zip,manager,manager username,currency
|
||||
Peace River,8 Brentwood Court,,Birendranagar,AB,CA,T8S,Danika Mostyn,dmostyn0,CAD
|
||||
Airdrie,14 Summer Ridge Court,306 Buhler Parkway,Poniatowa,AB,CA,T4B,Clementina Van Halen,cvan1,CAD
|
||||
Calgary,3 Fieldstone Drive,,Iwanai,AB,CA,,Harwilll Heffernan,hheffernan2,CAD
|
||||
High Prairie,1906 Weeping Birch Park,,Lopar,AB,CA,,Christian Pache,cpache3,CAD
|
||||
Sundre,20 Summer Ridge Court,,Burujul,AB,CA,,,,
|
||||
Athabasca,22 Browning Drive,424 Rieder Court,Itambacuri,AB,CA,,Alphonso Ashbridge,aashbridge5,CAD
|
||||
Drayton Valley,56064 Onsgard Center,,Bahía Honda,AB,CA,,,,
|
||||
Crossfield,0 Lighthouse Bay Place,,Bengras,AB,CA,,Vania Dufton,vdufton7,CAD
|
||||
Beaverlodge,6 Katie Terrace,,Zhajin,AB,CA,,Papageno Baldi,pbaldi8,CAD
|
||||
Grande Prairie,0 Ridgeview Parkway,,Yunxi,AB,CA,R3J,Selia Biggadike,sbiggadike9,CAD
|
||||
Sherwood Park,263 Aberg Alley,,El Paso,AB,CA,,,,
|
||||
Vegreville,9039 Shoshone Parkway,,Huazhou,AB,CA,,Georgy Eversfield,geversfieldb,CAD
|
||||
Rocky Mountain House,8617 Arapahoe Parkway,,Paraipaba,AB,CA,,Mara Gilfoyle,mgilfoylec,CAD
|
||||
Calmar,14 Green Ridge Circle,,Medveditskiy,AB,CA,S0G,Paulette Rylatt,prylattd,CAD
|
||||
Rocky Mountain House,517 Bowman Terrace,,Viana,AB,CA,,Neal Gabitis,ngabitise,CAD
|
||||
Pincher Creek,6054 Anzinger Hill,,Chlumec,AB,CA,,Bonnee Fowle,bfowlef,CAD
|
||||
Airdrie,8 Lien Drive,,Reims,AB,CA,,Kerry Aherne,kaherneg,CAD
|
||||
Camrose,4 Summit Parkway,,Xinqiao,AB,CA,T4V,Sherlock Stobbart,sstobbarth,CAD
|
||||
Lamont,12 Ilene Park,,Huangtang,AB,CA,N2E,Karlotta Pinckstone,kpinckstonei,CAD
|
|
Loading…
Reference in a new issue