diff --git a/app/Http/Controllers/Api/ImportController.php b/app/Http/Controllers/Api/ImportController.php index 6f5fc05ff3..914c16f8da 100644 --- a/app/Http/Controllers/Api/ImportController.php +++ b/app/Http/Controllers/Api/ImportController.php @@ -193,6 +193,9 @@ class ImportController extends Controller case 'user': $redirectTo = 'users.index'; break; + case 'location': + $redirectTo = 'locations.index'; + break; } if ($errors) { //Failure diff --git a/app/Http/Livewire/Importer.php b/app/Http/Livewire/Importer.php index 784d3b2982..e11dd060e9 100644 --- a/app/Http/Livewire/Importer.php +++ b/app/Http/Livewire/Importer.php @@ -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); } diff --git a/app/Importer/Importer.php b/app/Importer/Importer.php index 1ee90b399c..dfc8084666 100644 --- a/app/Importer/Importer.php +++ b/app/Importer/Importer.php @@ -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; diff --git a/app/Importer/ItemImporter.php b/app/Importer/ItemImporter.php index 7848ec6b85..f989457dc6 100644 --- a/app/Importer/ItemImporter.php +++ b/app/Importer/ItemImporter.php @@ -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'))); } diff --git a/app/Importer/LocationImporter.php b/app/Importer/LocationImporter.php new file mode 100644 index 0000000000..25140abe00 --- /dev/null +++ b/app/Importer/LocationImporter.php @@ -0,0 +1,102 @@ +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; + } + + + } +} \ No newline at end of file diff --git a/app/Models/Location.php b/app/Models/Location.php index 8cea9bda12..c3ddaa7598 100755 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -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', ]; diff --git a/sample_csvs/MOCK_LOCATIONS.csv b/sample_csvs/MOCK_LOCATIONS.csv new file mode 100644 index 0000000000..42285f2168 --- /dev/null +++ b/sample_csvs/MOCK_LOCATIONS.csv @@ -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