ok
This commit is contained in:
58
Production/SNIPE-IT/app/Importer/AccessoryImporter.php
Normal file
58
Production/SNIPE-IT/app/Importer/AccessoryImporter.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Accessory;
|
||||
|
||||
class AccessoryImporter extends ItemImporter
|
||||
{
|
||||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
{
|
||||
parent::handle($row); // TODO: Change the autogenerated stub
|
||||
$this->createAccessoryIfNotExists($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an accessory if a duplicate does not exist
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
*/
|
||||
public function createAccessoryIfNotExists($row)
|
||||
{
|
||||
$accessory = Accessory::where('name', $this->item['name'])->first();
|
||||
if ($accessory) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching Accessory '.$this->item['name'].' already exists. ');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log('Updating Accessory');
|
||||
$this->item['model_number'] = trim($this->findCsvMatch($row, "model_number"));
|
||||
$accessory->update($this->sanitizeItemForUpdating($accessory));
|
||||
$accessory->save();
|
||||
|
||||
return;
|
||||
}
|
||||
$this->log('No Matching Accessory, Creating a new one');
|
||||
$accessory = new Accessory();
|
||||
$this->item['model_number'] = $this->findCsvMatch($row, "model_number");
|
||||
$this->item['min_amt'] = $this->findCsvMatch($row, "min_amt");
|
||||
$accessory->fill($this->sanitizeItemForStoring($accessory));
|
||||
|
||||
// This sets an attribute on the Loggable trait for the action log
|
||||
$accessory->setImported(true);
|
||||
if ($accessory->save()) {
|
||||
$this->log('Accessory '.$this->item['name'].' was created');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->logError($accessory, 'Accessory');
|
||||
}
|
||||
}
|
161
Production/SNIPE-IT/app/Importer/AssetImporter.php
Normal file
161
Production/SNIPE-IT/app/Importer/AssetImporter.php
Normal file
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class AssetImporter extends ItemImporter
|
||||
{
|
||||
protected $defaultStatusLabelId;
|
||||
|
||||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
|
||||
if (!is_null(Statuslabel::first())) {
|
||||
$this->defaultStatusLabelId = Statuslabel::first()->id;
|
||||
}
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
{
|
||||
// ItemImporter handles the general fetching.
|
||||
parent::handle($row);
|
||||
|
||||
if ($this->customFields) {
|
||||
foreach ($this->customFields as $customField) {
|
||||
$customFieldValue = $this->array_smart_custom_field_fetch($row, $customField);
|
||||
|
||||
if ($customFieldValue) {
|
||||
if ($customField->field_encrypted == 1) {
|
||||
$this->item['custom_fields'][$customField->db_column_name()] = \Crypt::encrypt($customFieldValue);
|
||||
$this->log('Custom Field '.$customField->name.': '.\Crypt::encrypt($customFieldValue));
|
||||
} else {
|
||||
$this->item['custom_fields'][$customField->db_column_name()] = $customFieldValue;
|
||||
$this->log('Custom Field '.$customField->name.': '.$customFieldValue);
|
||||
}
|
||||
} else {
|
||||
// Clear out previous data.
|
||||
$this->item['custom_fields'][$customField->db_column_name()] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->createAssetIfNotExists($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the asset if it does not exist.
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param array $row
|
||||
* @return Asset|mixed|null
|
||||
*/
|
||||
public function createAssetIfNotExists(array $row)
|
||||
{
|
||||
$editingAsset = false;
|
||||
$asset_tag = $this->findCsvMatch($row, 'asset_tag');
|
||||
|
||||
if(empty($asset_tag)){
|
||||
$asset_tag = Asset::autoincrement_asset();
|
||||
}
|
||||
|
||||
|
||||
$asset = Asset::where(['asset_tag'=> (string) $asset_tag])->first();
|
||||
if ($asset) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching Asset '.$asset_tag.' already exists');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log('Updating Asset');
|
||||
$editingAsset = true;
|
||||
} else {
|
||||
$this->log('No Matching Asset, Creating a new one');
|
||||
$asset = new Asset;
|
||||
}
|
||||
$this->item['notes'] = trim($this->findCsvMatch($row, 'asset_notes'));
|
||||
$this->item['image'] = trim($this->findCsvMatch($row, 'image'));
|
||||
$this->item['requestable'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'))) == 1) ? '1' : 0;
|
||||
$asset->requestable = $this->item['requestable'];
|
||||
$this->item['warranty_months'] = intval(trim($this->findCsvMatch($row, 'warranty_months')));
|
||||
$this->item['model_id'] = $this->createOrFetchAssetModel($row);
|
||||
$this->item['byod'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'byod'))) == 1) ? '1' : 0;
|
||||
|
||||
|
||||
// If no status ID is found
|
||||
if (! array_key_exists('status_id', $this->item) && ! $editingAsset) {
|
||||
$this->log('No status field found, defaulting to first status.');
|
||||
$this->item['status_id'] = $this->defaultStatusLabelId;
|
||||
}
|
||||
|
||||
$this->item['asset_tag'] = $asset_tag;
|
||||
|
||||
// We need to save the user if it exists so that we can checkout to user later.
|
||||
// Sanitizing the item will remove it.
|
||||
if (array_key_exists('checkout_target', $this->item)) {
|
||||
$target = $this->item['checkout_target'];
|
||||
}
|
||||
$item = $this->sanitizeItemForStoring($asset, $editingAsset);
|
||||
// The location id fetched by the csv reader is actually the rtd_location_id.
|
||||
// This will also set location_id, but then that will be overridden by the
|
||||
// checkout method if necessary below.
|
||||
if (isset($this->item['location_id'])) {
|
||||
$item['rtd_location_id'] = $this->item['location_id'];
|
||||
}
|
||||
|
||||
$item['last_audit_date'] = null;
|
||||
if (isset($this->item['last_audit_date'])) {
|
||||
$item['last_audit_date'] = $this->item['last_audit_date'];
|
||||
}
|
||||
|
||||
$item['next_audit_date'] = null;
|
||||
if (isset($this->item['next_audit_date'])) {
|
||||
$item['next_audit_date'] = $this->item['next_audit_date'];
|
||||
}
|
||||
|
||||
if ($editingAsset) {
|
||||
$asset->update($item);
|
||||
} else {
|
||||
$asset->fill($item);
|
||||
}
|
||||
|
||||
// If we're updating, we don't want to overwrite old fields.
|
||||
if (array_key_exists('custom_fields', $this->item)) {
|
||||
foreach ($this->item['custom_fields'] as $custom_field => $val) {
|
||||
$asset->{$custom_field} = $val;
|
||||
}
|
||||
}
|
||||
// This sets an attribute on the Loggable trait for the action log
|
||||
$asset->setImported(true);
|
||||
if ($asset->save()) {
|
||||
|
||||
$this->log('Asset '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
||||
|
||||
// If we have a target to checkout to, lets do so.
|
||||
//-- user_id is a property of the abstract class Importer, which this class inherits from and it's setted by
|
||||
//-- the class that needs to use it (command importer or GUI importer inside the project).
|
||||
if (isset($target) && ($target !== false)) {
|
||||
if (!is_null($asset->assigned_to)){
|
||||
if ($asset->assigned_to != $target->id){
|
||||
event(new CheckoutableCheckedIn($asset, User::find($asset->assigned_to), Auth::user(), $asset->notes, date('Y-m-d H:i:s')));
|
||||
}
|
||||
}
|
||||
|
||||
$asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s'), null, $asset->notes, $asset->name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
$this->logError($asset, 'Asset "'.$this->item['name'].'"');
|
||||
}
|
||||
}
|
72
Production/SNIPE-IT/app/Importer/ComponentImporter.php
Normal file
72
Production/SNIPE-IT/app/Importer/ComponentImporter.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Component;
|
||||
|
||||
class ComponentImporter extends ItemImporter
|
||||
{
|
||||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
{
|
||||
parent::handle($row);
|
||||
$this->createComponentIfNotExists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a component if a duplicate does not exist
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
*/
|
||||
public function createComponentIfNotExists()
|
||||
{
|
||||
$component = null;
|
||||
$this->log('Creating Component');
|
||||
$component = Component::where('name', trim($this->item['name']))
|
||||
->where('serial', trim($this->item['serial']))
|
||||
->first();
|
||||
|
||||
if ($component) {
|
||||
$this->log('A matching Component '.$this->item['name'].' with serial '.$this->item['serial'].' already exists. ');
|
||||
if (! $this->updating) {
|
||||
$this->log('Skipping Component');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->log('Updating Component');
|
||||
$component->update($this->sanitizeItemForUpdating($component));
|
||||
$component->save();
|
||||
|
||||
return;
|
||||
}
|
||||
$this->log('No matching component, creating one');
|
||||
$component = new Component;
|
||||
$component->fill($this->sanitizeItemForStoring($component));
|
||||
|
||||
// This sets an attribute on the Loggable trait for the action log
|
||||
$component->setImported(true);
|
||||
if ($component->save()) {
|
||||
$this->log('Component '.$this->item['name'].' was created');
|
||||
|
||||
// If we have an asset tag, checkout to that asset.
|
||||
if (isset($this->item['asset_tag']) && ($asset = Asset::where('asset_tag', $this->item['asset_tag'])->first())) {
|
||||
$component->assets()->attach($component->id, [
|
||||
'component_id' => $component->id,
|
||||
'user_id' => $this->user_id,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'assigned_qty' => 1, // Only assign the first one to the asset
|
||||
'asset_id' => $asset->id,
|
||||
]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
$this->logError($component, 'Component');
|
||||
}
|
||||
}
|
58
Production/SNIPE-IT/app/Importer/ConsumableImporter.php
Normal file
58
Production/SNIPE-IT/app/Importer/ConsumableImporter.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Consumable;
|
||||
|
||||
class ConsumableImporter extends ItemImporter
|
||||
{
|
||||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
{
|
||||
parent::handle($row);
|
||||
$this->createConsumableIfNotExists($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a consumable if a duplicate does not exist
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @param array $row CSV Row Being parsed.
|
||||
* @since 3.0
|
||||
*/
|
||||
public function createConsumableIfNotExists($row)
|
||||
{
|
||||
$consumable = Consumable::where('name', trim($this->item['name']))->first();
|
||||
if ($consumable) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching Consumable '.$this->item['name'].' already exists. ');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->log('Updating Consumable');
|
||||
$consumable->update($this->sanitizeItemForUpdating($consumable));
|
||||
$consumable->save();
|
||||
|
||||
return;
|
||||
}
|
||||
$this->log('No matching consumable, creating one');
|
||||
$consumable = new Consumable();
|
||||
$this->item['model_number'] = trim($this->findCsvMatch($row, 'model_number'));
|
||||
$this->item['item_no'] = trim($this->findCsvMatch($row, 'item_number'));
|
||||
$this->item['min_amt'] = trim($this->findCsvMatch($row, "min_amt"));
|
||||
$consumable->fill($this->sanitizeItemForStoring($consumable));
|
||||
|
||||
// This sets an attribute on the Loggable trait for the action log
|
||||
$consumable->setImported(true);
|
||||
if ($consumable->save()) {
|
||||
$this->log('Consumable '.$this->item['name'].' was created');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->logError($consumable, 'Consumable');
|
||||
}
|
||||
}
|
553
Production/SNIPE-IT/app/Importer/Importer.php
Normal file
553
Production/SNIPE-IT/app/Importer/Importer.php
Normal file
@ -0,0 +1,553 @@
|
||||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use App\Models\Department;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use ForceUTF8\Encoding;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use League\Csv\Reader;
|
||||
|
||||
abstract class Importer
|
||||
{
|
||||
protected $csv;
|
||||
/**
|
||||
* Id of User performing import
|
||||
* @var
|
||||
*/
|
||||
|
||||
protected $user_id;
|
||||
/**
|
||||
* Are we updating items in the import
|
||||
* @var bool
|
||||
*/
|
||||
|
||||
protected $updating;
|
||||
|
||||
/**
|
||||
* Default Map of item fields->csv names
|
||||
*
|
||||
* This has been moved into app/Http/Livewire/Importer.php to be more granular.
|
||||
* This private variable is ONLY used for the cli-importer.
|
||||
*
|
||||
* @todo - find a way to make this less duplicative
|
||||
* @var array
|
||||
*/
|
||||
private $defaultFieldMap = [
|
||||
'asset_tag' => 'asset tag',
|
||||
'activated' => 'activated',
|
||||
'category' => 'category',
|
||||
'checkout_class' => 'checkout type', // Supports Location or User for assets. Using checkout_class instead of checkout_type because type exists on asset already.
|
||||
'checkout_location' => 'checkout location',
|
||||
'company' => 'company',
|
||||
'item_name' => 'item name',
|
||||
'item_number' => 'item number',
|
||||
'image' => 'image',
|
||||
'expiration_date' => 'expiration date',
|
||||
'location' => 'location',
|
||||
'notes' => 'notes',
|
||||
'license_email' => 'licensed to email',
|
||||
'license_name' => 'licensed to name',
|
||||
'maintained' => 'maintained',
|
||||
'manufacturer' => 'manufacturer',
|
||||
'asset_model' => 'model name',
|
||||
'model_number' => 'model number',
|
||||
'order_number' => 'order number',
|
||||
'purchase_cost' => 'purchase cost',
|
||||
'purchase_date' => 'purchase date',
|
||||
'purchase_order' => 'purchase order',
|
||||
'qty' => 'quantity',
|
||||
'reassignable' => 'reassignable',
|
||||
'requestable' => 'requestable',
|
||||
'seats' => 'seats',
|
||||
'serial' => 'serial number',
|
||||
'status' => 'status',
|
||||
'supplier' => 'supplier',
|
||||
'termination_date' => 'termination date',
|
||||
'warranty_months' => 'warranty',
|
||||
'full_name' => 'full name',
|
||||
'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_name' => 'manager full name',
|
||||
'manager_username' => 'manager username',
|
||||
'min_amt' => 'minimum quantity',
|
||||
'remote' => 'remote',
|
||||
'vip' => 'vip',
|
||||
];
|
||||
/**
|
||||
* Map of item fields->csv names
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldMap = [];
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $logCallback;
|
||||
protected $tempPassword;
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $progressCallback;
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
protected $usernameFormat;
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $errorCallback;
|
||||
|
||||
/**
|
||||
* ObjectImporter constructor.
|
||||
* @param string $file
|
||||
*/
|
||||
public function __construct($file)
|
||||
{
|
||||
$this->fieldMap = $this->defaultFieldMap;
|
||||
if (! ini_get('auto_detect_line_endings')) {
|
||||
ini_set('auto_detect_line_endings', '1');
|
||||
}
|
||||
// By default the importer passes a url to the file.
|
||||
// However, for testing we also support passing a string directly
|
||||
if (is_file($file)) {
|
||||
$this->csv = Reader::createFromPath($file);
|
||||
} else {
|
||||
$this->csv = Reader::createFromString($file);
|
||||
}
|
||||
$this->tempPassword = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 40);
|
||||
}
|
||||
|
||||
// Cached Values for import lookups
|
||||
protected $customFields;
|
||||
|
||||
/**
|
||||
* Sets up the database transaction and logging for the importer
|
||||
*
|
||||
* @return void
|
||||
* @author Daniel Meltzer
|
||||
* @since 5.0
|
||||
*/
|
||||
public function import()
|
||||
{
|
||||
$headerRow = $this->csv->fetchOne();
|
||||
$this->csv->setHeaderOffset(0); //explicitly sets the CSV document header record
|
||||
$results = $this->normalizeInputArray($this->csv->getRecords($headerRow));
|
||||
|
||||
$this->populateCustomFields($headerRow);
|
||||
|
||||
DB::transaction(function () use (&$results) {
|
||||
Model::unguard();
|
||||
$resultsCount = count($results);
|
||||
foreach ($results as $row) {
|
||||
$this->handle($row);
|
||||
if ($this->progressCallback) {
|
||||
call_user_func($this->progressCallback, $resultsCount);
|
||||
}
|
||||
|
||||
$this->log('------------- Action Summary ----------------');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
abstract protected function handle($row);
|
||||
|
||||
/**
|
||||
* Fetch custom fields from database and translate/parse them into a format
|
||||
* appropriate for use in the importer.
|
||||
* @return void
|
||||
* @author Daniel Meltzer
|
||||
* @since 5.0
|
||||
*/
|
||||
protected function populateCustomFields($headerRow)
|
||||
{
|
||||
// Stolen From https://adamwathan.me/2016/07/14/customizing-keys-when-mapping-collections/
|
||||
// This 'inverts' the fields such that we have a collection of fields indexed by name.
|
||||
$this->customFields = CustomField::All()->reduce(function ($nameLookup, $field) {
|
||||
$nameLookup[$field['name']] = $field;
|
||||
|
||||
return $nameLookup;
|
||||
});
|
||||
// Remove any custom fields that do not exist in the header row. This prevents nulling out values that shouldn't exist.
|
||||
// In detail, we compare the lower case name of custom fields (indexed by name) to the keys in the header row. This
|
||||
// results in an array with only custom fields that are in the file.
|
||||
if ($this->customFields) {
|
||||
$this->customFields = array_intersect_key(
|
||||
array_change_key_case($this->customFields),
|
||||
array_change_key_case(array_flip($headerRow))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the given key exists in the array, and trim excess white space before returning it
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param $array array
|
||||
* @param $key string
|
||||
* @param $default string
|
||||
* @return string
|
||||
*/
|
||||
public function findCsvMatch(array $array, $key, $default = null)
|
||||
{
|
||||
$val = $default;
|
||||
$key = $this->lookupCustomKey($key);
|
||||
|
||||
// $this->log("Custom Key: ${key}");
|
||||
if (array_key_exists($key, $array)) {
|
||||
$val = Encoding::toUTF8(trim($array[$key]));
|
||||
}
|
||||
//$this->log("${key}: ${val}");
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up A custom key in the custom field map
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 4.0
|
||||
* @param $key string
|
||||
* @return string|null
|
||||
*/
|
||||
public function lookupCustomKey($key)
|
||||
{
|
||||
if (array_key_exists($key, $this->fieldMap)) {
|
||||
return $this->fieldMap[$key];
|
||||
}
|
||||
// Otherwise no custom key, return original.
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to lowercase header values to ensure we're comparing values properly.
|
||||
*
|
||||
* @param $results
|
||||
* @return array
|
||||
*/
|
||||
public function normalizeInputArray($results)
|
||||
{
|
||||
$newArray = [];
|
||||
foreach ($results as $index => $arrayToNormalize) {
|
||||
$newArray[$index] = array_change_key_case($arrayToNormalize);
|
||||
}
|
||||
|
||||
return $newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Figure out the fieldname of the custom field
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since 3.0
|
||||
* @param $array array
|
||||
* @return string
|
||||
*/
|
||||
public function array_smart_custom_field_fetch(array $array, $key)
|
||||
{
|
||||
$index_name = strtolower($key->name);
|
||||
|
||||
return array_key_exists($index_name, $array) ? trim($array[$index_name]) : false;
|
||||
}
|
||||
|
||||
protected function log($string)
|
||||
{
|
||||
if ($this->logCallback) {
|
||||
call_user_func($this->logCallback, $string);
|
||||
}
|
||||
}
|
||||
|
||||
protected function logError($item, $field)
|
||||
{
|
||||
if ($this->errorCallback) {
|
||||
call_user_func($this->errorCallback, $item, $field, $item->getErrors());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the user matching given data, or creates a new one if there is no match.
|
||||
* This is NOT used by the User Import, only for Asset/Accessory/etc where
|
||||
* there are users listed and we have to create them and associate them at
|
||||
* the same time. [ALG]
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param $row array
|
||||
* @return User Model w/ matching name
|
||||
* @internal param array $user_array User details parsed from csv
|
||||
*/
|
||||
protected function createOrFetchUser($row, $type = 'user')
|
||||
{
|
||||
|
||||
$user_array = [
|
||||
'full_name' => $this->findCsvMatch($row, 'full_name'),
|
||||
'first_name' => $this->findCsvMatch($row, 'first_name'),
|
||||
'last_name' => $this->findCsvMatch($row, 'last_name'),
|
||||
'email' => $this->findCsvMatch($row, 'email'),
|
||||
'manager_id'=> '',
|
||||
'department_id' => '',
|
||||
'username' => $this->findCsvMatch($row, 'username'),
|
||||
'activated' => $this->fetchHumanBoolean($this->findCsvMatch($row, 'activated')),
|
||||
'remote' => $this->fetchHumanBoolean(($this->findCsvMatch($row, 'remote'))),
|
||||
];
|
||||
|
||||
if ($type == 'manager') {
|
||||
$user_array['full_name'] = $this->findCsvMatch($row, 'manager');
|
||||
$user_array['username'] = $this->findCsvMatch($row, 'manager_username');
|
||||
}
|
||||
|
||||
// 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'])) && (empty($user_array['first_name']))) {
|
||||
$this->log('Insufficient user data provided (Full name, first name or username is required) - skipping user creation.');
|
||||
\Log::debug('User array: ');
|
||||
\Log::debug(print_r($user_array, true));
|
||||
\Log::debug(print_r($row, true));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Populate email if it does not exist.
|
||||
if (empty($user_array['email'])) {
|
||||
$user_array['email'] = User::generateEmailFromFullName($user_array['full_name']);
|
||||
}
|
||||
|
||||
// Get some variables for $user_formatted_array in case we need them later
|
||||
$user_formatted_array = User::generateFormattedNameFromFullName($user_array['full_name'], Setting::getSettings()->username_format);
|
||||
|
||||
if (empty($user_array['first_name'])) {
|
||||
// Get some fields for first name and last name based off of full name
|
||||
$user_array['first_name'] = $user_formatted_array['first_name'];
|
||||
$user_array['last_name'] = $user_formatted_array['last_name'];
|
||||
}
|
||||
|
||||
if (empty($user_array['username'])) {
|
||||
$user_array['username'] = $user_formatted_array['username'];
|
||||
if ($this->usernameFormat == 'email') {
|
||||
$user_array['username'] = $user_array['email'];
|
||||
}
|
||||
|
||||
// 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.
|
||||
if (empty($user_array['username']) || empty($user_array['first_name'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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'];
|
||||
$user->username = $user_array['username'];
|
||||
$user->email = $user_array['email'];
|
||||
$user->manager_id = $user_array['manager_id'] ?? null;
|
||||
$user->department_id = $user_array['department_id'] ?? null;
|
||||
$user->activated = 1;
|
||||
$user->password = $this->tempPassword;
|
||||
|
||||
\Log::debug('Creating a user with the following attributes: '.print_r($user_array, true));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a user by user_id if user_name provided is a number
|
||||
* @param string $user_name users full name from csv
|
||||
* @return User User Matching ID
|
||||
*/
|
||||
protected function findUserByNumber($user_name)
|
||||
{
|
||||
// A number was given instead of a name
|
||||
if (is_numeric($user_name)) {
|
||||
$this->log('User '.$user_name.' is a number - lets see if it matches a user id');
|
||||
|
||||
return User::find($user_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Id of User performing import.
|
||||
*
|
||||
* @param mixed $user_id the user id
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setUserId($user_id)
|
||||
{
|
||||
$this->user_id = $user_id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Are we updating items in the import.
|
||||
*
|
||||
* @param bool $updating the updating
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setUpdating($updating)
|
||||
{
|
||||
$this->updating = $updating;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not we should notify the user with a welcome email
|
||||
*
|
||||
* @param bool $send_welcome the send-welcome flag
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setShouldNotify($send_welcome)
|
||||
{
|
||||
$this->send_welcome = $send_welcome;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines mappings of csv fields
|
||||
*
|
||||
* @param bool $updating the updating
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setFieldMappings($fields)
|
||||
{
|
||||
// Some initial sanitization.
|
||||
$fields = array_map('strtolower', $fields);
|
||||
$this->fieldMap = array_merge($this->defaultFieldMap, $fields);
|
||||
|
||||
// $this->log($this->fieldMap);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the callbacks for the import
|
||||
*
|
||||
* @param callable $logCallback Function to call when we have data to log
|
||||
* @param callable $progressCallback Function to call to display progress
|
||||
* @param callable $errorCallback Function to call when we have errors
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setCallbacks(callable $logCallback, callable $progressCallback, callable $errorCallback)
|
||||
{
|
||||
$this->logCallback = $logCallback;
|
||||
$this->progressCallback = $progressCallback;
|
||||
$this->errorCallback = $errorCallback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of usernameFormat.
|
||||
*
|
||||
* @param string $usernameFormat the username format
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setUsernameFormat($usernameFormat)
|
||||
{
|
||||
$this->usernameFormat = $usernameFormat;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fetchHumanBoolean($value)
|
||||
{
|
||||
return (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an existing department, or create new if it doesn't exist
|
||||
*
|
||||
* @author A. Gianotto
|
||||
* @since 4.6.5
|
||||
* @param $user_department string
|
||||
* @return int id of company created/found
|
||||
*/
|
||||
public function createOrFetchDepartment($user_department_name)
|
||||
{
|
||||
if ($user_department_name != '') {
|
||||
$department = Department::where('name', '=', $user_department_name)->first();
|
||||
|
||||
if ($department) {
|
||||
$this->log('A matching Department '.$user_department_name.' already exists');
|
||||
|
||||
return $department->id;
|
||||
}
|
||||
|
||||
$department = new Department();
|
||||
$department->name = $user_department_name;
|
||||
|
||||
if ($department->save()) {
|
||||
$this->log('Department '.$user_department_name.' was created');
|
||||
|
||||
return $department->id;
|
||||
}
|
||||
$this->logError($department, 'Department');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an existing manager
|
||||
*
|
||||
* @author A. Gianotto
|
||||
* @since 4.6.5
|
||||
* @param $user_manager string
|
||||
* @return int id of company created/found
|
||||
*/
|
||||
public function fetchManager($user_manager_first_name, $user_manager_last_name)
|
||||
{
|
||||
$manager = User::where('first_name', '=', $user_manager_first_name)
|
||||
->where('last_name', '=', $user_manager_last_name)->first();
|
||||
if ($manager) {
|
||||
$this->log('A matching Manager '.$user_manager_first_name.' '.$user_manager_last_name.' already exists');
|
||||
|
||||
return $manager->id;
|
||||
}
|
||||
$this->log('No matching Manager '.$user_manager_first_name.' '.$user_manager_last_name.' found. If their user account is being created through this import, you should re-process this file again. ');
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
512
Production/SNIPE-IT/app/Importer/ItemImporter.php
Normal file
512
Production/SNIPE-IT/app/Importer/ItemImporter.php
Normal file
@ -0,0 +1,512 @@
|
||||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\Manufacturer;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ItemImporter extends Importer
|
||||
{
|
||||
protected $item;
|
||||
|
||||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
{
|
||||
// Need to reset this between iterations or we'll have stale data.
|
||||
$this->item = [];
|
||||
|
||||
$item_category = $this->findCsvMatch($row, 'category');
|
||||
if ($this->shouldUpdateField($item_category)) {
|
||||
$this->item['category_id'] = $this->createOrFetchCategory($item_category);
|
||||
}
|
||||
|
||||
$item_company_name = $this->findCsvMatch($row, 'company');
|
||||
if ($this->shouldUpdateField($item_company_name)) {
|
||||
$this->item['company_id'] = $this->createOrFetchCompany($item_company_name);
|
||||
}
|
||||
|
||||
$item_location = $this->findCsvMatch($row, 'location');
|
||||
if ($this->shouldUpdateField($item_location)) {
|
||||
$this->item['location_id'] = $this->createOrFetchLocation($item_location);
|
||||
}
|
||||
|
||||
$item_manufacturer = $this->findCsvMatch($row, 'manufacturer');
|
||||
if ($this->shouldUpdateField($item_manufacturer)) {
|
||||
$this->item['manufacturer_id'] = $this->createOrFetchManufacturer($item_manufacturer);
|
||||
}
|
||||
|
||||
$item_status_name = $this->findCsvMatch($row, 'status');
|
||||
if ($this->shouldUpdateField($item_status_name)) {
|
||||
$this->item['status_id'] = $this->createOrFetchStatusLabel($item_status_name);
|
||||
}
|
||||
|
||||
$item_supplier = $this->findCsvMatch($row, 'supplier');
|
||||
if ($this->shouldUpdateField($item_supplier)) {
|
||||
$this->item['supplier_id'] = $this->createOrFetchSupplier($item_supplier);
|
||||
}
|
||||
|
||||
$item_department = $this->findCsvMatch($row, 'department');
|
||||
if ($this->shouldUpdateField($item_department)) {
|
||||
$this->item['department_id'] = $this->createOrFetchDepartment($item_department);
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
$this->item['name'] = $this->findCsvMatch($row, 'item_name');
|
||||
$this->item['notes'] = $this->findCsvMatch($row, 'notes');
|
||||
$this->item['order_number'] = $this->findCsvMatch($row, 'order_number');
|
||||
$this->item['purchase_cost'] = $this->findCsvMatch($row, 'purchase_cost');
|
||||
|
||||
$this->item['purchase_date'] = null;
|
||||
if ($this->findCsvMatch($row, 'purchase_date') != '') {
|
||||
$this->item['purchase_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'purchase_date')));
|
||||
}
|
||||
|
||||
$this->item['last_audit_date'] = null;
|
||||
if ($this->findCsvMatch($row, 'last_audit_date') != '') {
|
||||
$this->item['last_audit_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'last_audit_date')));
|
||||
}
|
||||
|
||||
$this->item['next_audit_date'] = null;
|
||||
if ($this->findCsvMatch($row, 'next_audit_date') != '') {
|
||||
$this->item['next_audit_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'next_audit_date')));
|
||||
}
|
||||
|
||||
$this->item['asset_eol_date'] = null;
|
||||
if($this->findCsvMatch($row, 'asset_eol_date') != '') {
|
||||
$csvMatch = $this->findCsvMatch($row, 'asset_eol_date');
|
||||
try {
|
||||
$this->item['asset_eol_date'] = CarbonImmutable::parse($csvMatch)->format('Y-m-d');
|
||||
} catch (\Exception $e) {
|
||||
Log::info($e->getMessage());
|
||||
$this->log('Unable to parse date: '.$csvMatch);
|
||||
}
|
||||
}
|
||||
|
||||
$this->item['qty'] = $this->findCsvMatch($row, 'quantity');
|
||||
$this->item['requestable'] = $this->findCsvMatch($row, 'requestable');
|
||||
$this->item['user_id'] = $this->user_id;
|
||||
$this->item['serial'] = $this->findCsvMatch($row, 'serial');
|
||||
// NO need to call this method if we're running the user import.
|
||||
// TODO: Merge these methods.
|
||||
$this->item['checkout_class'] = $this->findCsvMatch($row, 'checkout_class');
|
||||
if (get_class($this) !== UserImporter::class) {
|
||||
// $this->item["user"] = $this->createOrFetchUser($row);
|
||||
$this->item['checkout_target'] = $this->determineCheckout($row);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse row to determine what (if anything) we should checkout to.
|
||||
* @param array $row CSV Row being parsed
|
||||
* @return ?SnipeModel Model to be checked out to
|
||||
*/
|
||||
protected function determineCheckout($row)
|
||||
{
|
||||
// Locations don't get checked out to anyone/anything
|
||||
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')));
|
||||
}
|
||||
|
||||
return $this->createOrFetchUser($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup the $item array before storing.
|
||||
* We need to remove any values that are not part of the fillable fields.
|
||||
* Also, if updating, we remove any fields from the array that are empty.
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 4.0
|
||||
* @param $model SnipeModel Model that's being updated.
|
||||
* @param $updating boolean Should we remove blank values?
|
||||
* @return array
|
||||
*/
|
||||
protected function sanitizeItemForStoring($model, $updating = false)
|
||||
{
|
||||
// Create a collection for all manipulations to come.
|
||||
$item = collect($this->item);
|
||||
// First Filter the item down to the model's fillable fields
|
||||
$item = $item->only($model->getFillable());
|
||||
|
||||
// Then iterate through the item and, if we are updating, remove any blank values.
|
||||
if ($updating) {
|
||||
$item = $item->reject(function ($value) {
|
||||
return empty($value);
|
||||
});
|
||||
}
|
||||
|
||||
return $item->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for updating that strips the empty values.
|
||||
* @param $model SnipeModel Model that's being updated.
|
||||
* @return array
|
||||
*/
|
||||
protected function sanitizeItemForUpdating($model)
|
||||
{
|
||||
return $this->sanitizeItemForStoring($model, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a field needs updating
|
||||
* Follows the following rules:
|
||||
* If we are not updating, we should update the field
|
||||
* If We are updating, we only update the field if it's not empty.
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 4.0
|
||||
* @param $field string
|
||||
* @return bool
|
||||
*/
|
||||
protected function shouldUpdateField($field)
|
||||
{
|
||||
if (empty($field)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! ($this->updating && empty($field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the asset model if it exists, otherwise create it.
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param array
|
||||
* @param $row Row
|
||||
* @return int Id of asset model created/found
|
||||
* @internal param $asset_modelno string
|
||||
*/
|
||||
public function createOrFetchAssetModel(array $row)
|
||||
{
|
||||
$condition = array();
|
||||
$asset_model_name = $this->findCsvMatch($row, 'asset_model');
|
||||
$asset_modelNumber = $this->findCsvMatch($row, 'model_number');
|
||||
// TODO: At the moment, this means we can't update the model number if the model name stays the same.
|
||||
if (! $this->shouldUpdateField($asset_model_name)) {
|
||||
return;
|
||||
}
|
||||
if ((empty($asset_model_name)) && (! empty($asset_modelNumber))) {
|
||||
$asset_model_name = $asset_modelNumber;
|
||||
} elseif ((empty($asset_model_name)) && (empty($asset_modelNumber))) {
|
||||
$asset_model_name = 'Unknown';
|
||||
}
|
||||
|
||||
if ((!empty($asset_model_name)) && (empty($asset_modelNumber))) {
|
||||
$condition[] = ['name', '=', $asset_model_name];
|
||||
} elseif ((!empty($asset_model_name)) && (!empty($asset_modelNumber))) {
|
||||
$condition[] = ['name', '=', $asset_model_name];
|
||||
$condition[] = ['model_number', '=', $asset_modelNumber];
|
||||
}
|
||||
|
||||
$editingModel = $this->updating;
|
||||
$asset_model = AssetModel::where($condition)->first();
|
||||
|
||||
if ($asset_model) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching model already exists, returning it.');
|
||||
|
||||
return $asset_model->id;
|
||||
}
|
||||
$this->log('Matching Model found, updating it.');
|
||||
$item = $this->sanitizeItemForStoring($asset_model, $editingModel);
|
||||
$item['name'] = $asset_model_name;
|
||||
$item['notes'] = $this->findCsvMatch($row, 'model_notes');
|
||||
|
||||
if(!empty($asset_modelNumber)){
|
||||
$item['model_number'] = $asset_modelNumber;
|
||||
}
|
||||
|
||||
$asset_model->update($item);
|
||||
$asset_model->save();
|
||||
$this->log('Asset Model Updated');
|
||||
|
||||
return $asset_model->id;
|
||||
}
|
||||
$this->log('No Matching Model, Creating a new one');
|
||||
|
||||
$asset_model = new AssetModel();
|
||||
$item = $this->sanitizeItemForStoring($asset_model, $editingModel);
|
||||
$item['name'] = $asset_model_name;
|
||||
$item['model_number'] = $asset_modelNumber;
|
||||
$item['notes'] = $this->findCsvMatch($row, 'model_notes');
|
||||
|
||||
$asset_model->fill($item);
|
||||
$item = null;
|
||||
|
||||
if ($asset_model->save()) {
|
||||
$this->log('Asset Model '.$asset_model_name.' with model number '.$asset_modelNumber.' was created');
|
||||
|
||||
return $asset_model->id;
|
||||
}
|
||||
$this->logError($asset_model, 'Asset Model "'.$asset_model_name.'"');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a category with the same name and item type in the database, otherwise creates it
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param $asset_category string
|
||||
* @return int Id of category created/found
|
||||
* @internal param string $item_type
|
||||
*/
|
||||
public function createOrFetchCategory($asset_category)
|
||||
{
|
||||
// Magic to transform "AssetImporter" to "asset" or similar.
|
||||
$classname = class_basename(get_class($this));
|
||||
$item_type = strtolower(substr($classname, 0, strpos($classname, 'Importer')));
|
||||
|
||||
if (empty($asset_category)) {
|
||||
$asset_category = 'Unnamed Category';
|
||||
}
|
||||
$category = Category::where(['name' => $asset_category, 'category_type' => $item_type])->first();
|
||||
|
||||
if ($category) {
|
||||
$this->log('A matching category: '.$asset_category.' already exists');
|
||||
|
||||
return $category->id;
|
||||
}
|
||||
|
||||
$category = new Category();
|
||||
$category->name = $asset_category;
|
||||
$category->category_type = $item_type;
|
||||
$category->user_id = $this->user_id;
|
||||
|
||||
if ($category->save()) {
|
||||
$this->log('Category '.$asset_category.' was created');
|
||||
|
||||
return $category->id;
|
||||
}
|
||||
$this->logError($category, 'Category "'. $asset_category. '"');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an existing company, or create new if it doesn't exist
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param $asset_company_name string
|
||||
* @return int id of company created/found
|
||||
*/
|
||||
public function createOrFetchCompany($asset_company_name)
|
||||
{
|
||||
$company = Company::where(['name' => $asset_company_name])->first();
|
||||
if ($company) {
|
||||
$this->log('A matching Company '.$asset_company_name.' already exists');
|
||||
|
||||
return $company->id;
|
||||
}
|
||||
$company = new Company();
|
||||
$company->name = $asset_company_name;
|
||||
|
||||
if ($company->save()) {
|
||||
$this->log('Company '.$asset_company_name.' was created');
|
||||
|
||||
return $company->id;
|
||||
}
|
||||
$this->logError($company, 'Company');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an existing manager
|
||||
*
|
||||
* @author A. Gianotto
|
||||
* @since 4.6.5
|
||||
* @param $user_manager string
|
||||
* @return int id of company created/found
|
||||
*/
|
||||
public function fetchManager($user_manager_first_name, $user_manager_last_name)
|
||||
{
|
||||
$manager = User::where('first_name', '=', $user_manager_first_name)
|
||||
->where('last_name', '=', $user_manager_last_name)->first();
|
||||
if ($manager) {
|
||||
$this->log('A matching Manager '.$user_manager_first_name.' '.$user_manager_last_name.' already exists');
|
||||
|
||||
return $manager->id;
|
||||
}
|
||||
$this->log('No matching Manager '.$user_manager_first_name.' '.$user_manager_last_name.' found. If their user account is being created through this import, you should re-process this file again. ');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the existing status label or create new if it doesn't exist.
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param string $asset_statuslabel_name
|
||||
* @return Statuslabel|null
|
||||
*/
|
||||
public function createOrFetchStatusLabel($asset_statuslabel_name)
|
||||
{
|
||||
if (empty($asset_statuslabel_name)) {
|
||||
return null;
|
||||
}
|
||||
$status = Statuslabel::where(['name' => trim($asset_statuslabel_name)])->first();
|
||||
|
||||
if ($status) {
|
||||
$this->log('A matching Status '.$asset_statuslabel_name.' already exists');
|
||||
|
||||
return $status->id;
|
||||
}
|
||||
$this->log('Creating a new status');
|
||||
$status = new Statuslabel();
|
||||
$status->name = trim($asset_statuslabel_name);
|
||||
|
||||
$status->deployable = 1;
|
||||
$status->pending = 0;
|
||||
$status->archived = 0;
|
||||
|
||||
if ($status->save()) {
|
||||
$this->log('Status '.$asset_statuslabel_name.' was created');
|
||||
|
||||
return $status->id;
|
||||
}
|
||||
|
||||
$this->logError($status, 'Status "'.$asset_statuslabel_name.'"');
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a manufacturer with matching name, otherwise create it.
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param $item_manufacturer string
|
||||
* @return Manufacturer
|
||||
*/
|
||||
public function createOrFetchManufacturer($item_manufacturer)
|
||||
{
|
||||
if (empty($item_manufacturer)) {
|
||||
$item_manufacturer = 'Unknown';
|
||||
}
|
||||
$manufacturer = Manufacturer::where(['name'=> $item_manufacturer])->first();
|
||||
|
||||
if ($manufacturer) {
|
||||
$this->log('Manufacturer '.$item_manufacturer.' already exists');
|
||||
|
||||
return $manufacturer->id;
|
||||
}
|
||||
|
||||
//Otherwise create a manufacturer.
|
||||
$manufacturer = new Manufacturer();
|
||||
$manufacturer->name = trim($item_manufacturer);
|
||||
$manufacturer->user_id = $this->user_id;
|
||||
|
||||
if ($manufacturer->save()) {
|
||||
$this->log('Manufacturer '.$manufacturer->name.' was created');
|
||||
|
||||
return $manufacturer->id;
|
||||
}
|
||||
$this->logError($manufacturer, 'Manufacturer "'.$manufacturer->name.'"');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the DB to see if a location with the same name exists, otherwise create it
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param $asset_location string
|
||||
* @return Location|null
|
||||
*/
|
||||
public function createOrFetchLocation($asset_location)
|
||||
{
|
||||
if (empty($asset_location)) {
|
||||
$this->log('No location given, so none created.');
|
||||
|
||||
return null;
|
||||
}
|
||||
$location = Location::where(['name' => $asset_location])->first();
|
||||
|
||||
if ($location) {
|
||||
$this->log('Location '.$asset_location.' already exists');
|
||||
|
||||
return $location->id;
|
||||
}
|
||||
// No matching locations in the collection, create a new one.
|
||||
$location = new Location();
|
||||
$location->name = $asset_location;
|
||||
$location->address = '';
|
||||
$location->city = '';
|
||||
$location->state = '';
|
||||
$location->country = '';
|
||||
$location->user_id = $this->user_id;
|
||||
|
||||
if ($location->save()) {
|
||||
$this->log('Location '.$asset_location.' was created');
|
||||
|
||||
return $location->id;
|
||||
}
|
||||
$this->logError($location, 'Location');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an existing supplier or create new if it doesn't exist
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 3.0
|
||||
* @param $row array
|
||||
* @return Supplier
|
||||
*/
|
||||
public function createOrFetchSupplier($item_supplier)
|
||||
{
|
||||
if (empty($item_supplier)) {
|
||||
$item_supplier = 'Unknown';
|
||||
}
|
||||
|
||||
$supplier = Supplier::where(['name' => $item_supplier])->first();
|
||||
|
||||
if ($supplier) {
|
||||
$this->log('Supplier '.$item_supplier.' already exists');
|
||||
|
||||
return $supplier->id;
|
||||
}
|
||||
|
||||
$supplier = new Supplier();
|
||||
$supplier->name = $item_supplier;
|
||||
$supplier->user_id = $this->user_id;
|
||||
|
||||
if ($supplier->save()) {
|
||||
$this->log('Supplier '.$item_supplier.' was created');
|
||||
|
||||
return $supplier->id;
|
||||
}
|
||||
$this->logError($supplier, 'Supplier');
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
122
Production/SNIPE-IT/app/Importer/LicenseImporter.php
Normal file
122
Production/SNIPE-IT/app/Importer/LicenseImporter.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\License;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class LicenseImporter extends ItemImporter
|
||||
{
|
||||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
{
|
||||
// ItemImporter handles the general fetching.
|
||||
parent::handle($row);
|
||||
$this->createLicenseIfNotExists($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the license if it does not exist.
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 4.0
|
||||
* @param array $row
|
||||
* @return License|mixed|null
|
||||
* updated @author Jes Vinsmoke
|
||||
* @since 6.1
|
||||
*
|
||||
*/
|
||||
public function createLicenseIfNotExists(array $row)
|
||||
{
|
||||
$editingLicense = false;
|
||||
$license = License::where('serial', $this->item['serial'])->where('name', $this->item['name'])
|
||||
->first();
|
||||
if ($license) {
|
||||
if (! $this->updating) {
|
||||
|
||||
if($this->item['serial'] != "") {
|
||||
$this->log('A matching License ' . $this->item['name'] . ' with serial ' . $this->item['serial'] . ' already exists');
|
||||
}
|
||||
else {
|
||||
$this->log('A matching License ' . $this->item['name'] . ' with no serial number already exists');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log('Updating License');
|
||||
$editingLicense = true;
|
||||
} else {
|
||||
$this->log('No Matching License, Creating a new one');
|
||||
$license = new License;
|
||||
}
|
||||
$asset_tag = $this->item['asset_tag'] = trim($this->findCsvMatch($row, 'asset_tag')); // used for checkout out to an asset.
|
||||
|
||||
$this->item["expiration_date"] = null;
|
||||
if ($this->findCsvMatch($row, "expiration_date")!='') {
|
||||
$this->item["expiration_date"] = date("Y-m-d 00:00:01", strtotime(trim($this->findCsvMatch($row, "expiration_date"))));
|
||||
}
|
||||
$this->item['license_email'] = trim($this->findCsvMatch($row, 'license_email'));
|
||||
$this->item['license_name'] = trim($this->findCsvMatch($row, 'license_name'));
|
||||
$this->item['maintained'] = trim($this->findCsvMatch($row, 'maintained'));
|
||||
$this->item['purchase_order'] = trim($this->findCsvMatch($row, 'purchase_order'));
|
||||
$this->item['order_number'] = trim($this->findCsvMatch($row, 'order_number'));
|
||||
$this->item['reassignable'] = trim($this->findCsvMatch($row, 'reassignable'));
|
||||
$this->item['manufacturer'] = $this->createOrFetchManufacturer(trim($this->findCsvMatch($row, 'manufacturer')));
|
||||
|
||||
if($this->item['reassignable'] == "")
|
||||
{
|
||||
$this->item['reassignable'] = 1;
|
||||
}
|
||||
$this->item['seats'] = $this->findCsvMatch($row, 'seats');
|
||||
|
||||
$this->item["termination_date"] = null;
|
||||
if ($this->findCsvMatch($row, "termination_date")!='') {
|
||||
$this->item["termination_date"] = date("Y-m-d 00:00:01", strtotime($this->findCsvMatch($row, "termination_date")));
|
||||
}
|
||||
|
||||
if ($editingLicense) {
|
||||
$license->update($this->sanitizeItemForUpdating($license));
|
||||
} else {
|
||||
$license->fill($this->sanitizeItemForStoring($license));
|
||||
}
|
||||
|
||||
// This sets an attribute on the Loggable trait for the action log
|
||||
$license->setImported(true);
|
||||
if ($license->save()) {
|
||||
$this->log('License '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
||||
|
||||
// Lets try to checkout seats if the fields exist and we have seats.
|
||||
if ($license->seats > 0) {
|
||||
$checkout_target = $this->item['checkout_target'];
|
||||
$asset = Asset::where('asset_tag', $asset_tag)->first();
|
||||
$targetLicense = $license->freeSeat();
|
||||
|
||||
if (is_null($targetLicense)){
|
||||
return;
|
||||
}
|
||||
|
||||
if ($checkout_target) {
|
||||
$targetLicense->assigned_to = $checkout_target->id;
|
||||
$targetLicense->user_id = Auth::id();
|
||||
if ($asset) {
|
||||
$targetLicense->asset_id = $asset->id;
|
||||
}
|
||||
$targetLicense->save();
|
||||
} elseif ($asset) {
|
||||
$targetLicense->user_id = Auth::id();
|
||||
$targetLicense->asset_id = $asset->id;
|
||||
$targetLicense->save();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
$this->logError($license, 'License "'.$this->item['name'].'"');
|
||||
}
|
||||
}
|
102
Production/SNIPE-IT/app/Importer/LocationImporter.php
Normal file
102
Production/SNIPE-IT/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'] = trim($this->findCsvMatch($row, 'name'));
|
||||
$this->item['address'] = trim($this->findCsvMatch($row, 'address'));
|
||||
$this->item['address2'] = trim($this->findCsvMatch($row, 'address2'));
|
||||
$this->item['city'] = trim($this->findCsvMatch($row, 'city'));
|
||||
$this->item['state'] = trim($this->findCsvMatch($row, 'state'));
|
||||
$this->item['country'] = trim($this->findCsvMatch($row, 'country'));
|
||||
$this->item['zip'] = trim($this->findCsvMatch($row, 'zip'));
|
||||
$this->item['currency'] = trim($this->findCsvMatch($row, 'currency'));
|
||||
$this->item['ldap_ou'] = trim($this->findCsvMatch($row, 'ldap_ou'));
|
||||
$this->item['manager'] = trim($this->findCsvMatch($row, 'manager'));
|
||||
$this->item['manager_username'] = trim($this->findCsvMatch($row, 'manager_username'));
|
||||
$this->item['user_id'] = \Auth::user()->id;
|
||||
|
||||
if ($this->findCsvMatch($row, 'parent_location')) {
|
||||
$this->item['parent_id'] = $this->createOrFetchLocation(trim($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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
181
Production/SNIPE-IT/app/Importer/UserImporter.php
Normal file
181
Production/SNIPE-IT/app/Importer/UserImporter.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Department;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Notifications\WelcomeNotification;
|
||||
|
||||
/**
|
||||
* This is ONLY used for the User Import. When we are importing users
|
||||
* via an Asset/etc import, we use createOrFetchUser() in
|
||||
* App\Importer.php. [ALG]
|
||||
*
|
||||
* Class UserImporter
|
||||
*/
|
||||
class UserImporter extends ItemImporter
|
||||
{
|
||||
protected $users;
|
||||
protected $send_welcome = false;
|
||||
|
||||
public function __construct($filename)
|
||||
{
|
||||
parent::__construct($filename);
|
||||
}
|
||||
|
||||
protected function handle($row)
|
||||
{
|
||||
parent::handle($row);
|
||||
$this->createUserIfNotExists($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a user if a duplicate does not exist.
|
||||
* @todo Investigate how this should interact with Importer::createOrFetchUser
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 4.0
|
||||
* @param array $row
|
||||
*/
|
||||
public function createUserIfNotExists(array $row)
|
||||
{
|
||||
// Pull the records from the CSV to determine their values
|
||||
$this->item['id'] = trim($this->findCsvMatch($row, 'id'));
|
||||
$this->item['username'] = trim($this->findCsvMatch($row, 'username'));
|
||||
$this->item['first_name'] = trim($this->findCsvMatch($row, 'first_name'));
|
||||
$this->item['last_name'] = trim($this->findCsvMatch($row, 'last_name'));
|
||||
$this->item['email'] = trim($this->findCsvMatch($row, 'email'));
|
||||
$this->item['gravatar'] = trim($this->findCsvMatch($row, 'gravatar'));
|
||||
$this->item['phone'] = trim($this->findCsvMatch($row, 'phone_number'));
|
||||
$this->item['website'] = trim($this->findCsvMatch($row, 'website'));
|
||||
$this->item['jobtitle'] = trim($this->findCsvMatch($row, 'jobtitle'));
|
||||
$this->item['address'] = trim($this->findCsvMatch($row, 'address'));
|
||||
$this->item['city'] = trim($this->findCsvMatch($row, 'city'));
|
||||
$this->item['state'] = trim($this->findCsvMatch($row, 'state'));
|
||||
$this->item['country'] = trim($this->findCsvMatch($row, 'country'));
|
||||
$this->item['start_date'] = trim($this->findCsvMatch($row, 'start_date'));
|
||||
$this->item['end_date'] = trim($this->findCsvMatch($row, 'end_date'));
|
||||
$this->item['zip'] = trim($this->findCsvMatch($row, 'zip'));
|
||||
$this->item['activated'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'activated'))) == 1) ? '1' : 0;
|
||||
$this->item['employee_num'] = trim($this->findCsvMatch($row, 'employee_num'));
|
||||
$this->item['department_id'] = trim($this->createOrFetchDepartment(trim($this->findCsvMatch($row, 'department'))));
|
||||
$this->item['manager_id'] = $this->fetchManager(trim($this->findCsvMatch($row, 'manager_first_name')), trim($this->findCsvMatch($row, 'manager_last_name')));
|
||||
$this->item['remote'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'remote'))) == 1 ) ? '1' : 0;
|
||||
$this->item['vip'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'vip'))) ==1 ) ? '1' : 0;
|
||||
$this->item['autoassign_licenses'] = ($this->fetchHumanBoolean(trim($this->findCsvMatch($row, 'autoassign_licenses'))) ==1 ) ? '1' : 0;
|
||||
|
||||
|
||||
$user_department = trim($this->findCsvMatch($row, 'department'));
|
||||
if ($this->shouldUpdateField($user_department)) {
|
||||
$this->item['department_id'] = $this->createOrFetchDepartment($user_department);
|
||||
}
|
||||
|
||||
if (is_null($this->item['username']) || $this->item['username'] == "") {
|
||||
$user_full_name = $this->item['first_name'] . ' ' . $this->item['last_name'];
|
||||
$user_formatted_array = User::generateFormattedNameFromFullName($user_full_name, Setting::getSettings()->username_format);
|
||||
$this->item['username'] = $user_formatted_array['username'];
|
||||
}
|
||||
|
||||
// Check if a numeric ID was passed. If it does, use that above all else.
|
||||
if ((array_key_exists('id', $this->item) && ($this->item['id'] != "") && (is_numeric($this->item['id'])))) {
|
||||
$user = User::find($this->item['id']);
|
||||
} else {
|
||||
$user = User::where('username', $this->item['username'])->first();
|
||||
}
|
||||
|
||||
if ($user) {
|
||||
|
||||
if (! $this->updating) {
|
||||
\Log::debug('A matching User '.$this->item['name'].' already exists. ');
|
||||
return;
|
||||
}
|
||||
$this->log('Updating User');
|
||||
$user->update($this->sanitizeItemForUpdating($user));
|
||||
$user->save();
|
||||
|
||||
// Update the location of any assets checked out to this user
|
||||
Asset::where('assigned_type', User::class)
|
||||
->where('assigned_to', $user->id)
|
||||
->update(['location_id' => $user->location_id]);
|
||||
|
||||
// \Log::debug('UserImporter.php Updated User ' . print_r($user, true));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This needs to be applied after the update logic, otherwise we'll overwrite user passwords
|
||||
// Issue #5408
|
||||
$this->item['password'] = bcrypt($this->tempPassword);
|
||||
|
||||
$this->log('No matching user, creating one');
|
||||
$user = new User();
|
||||
$user->fill($this->sanitizeItemForStoring($user));
|
||||
|
||||
if ($user->save()) {
|
||||
$this->log('User '.$this->item['name'].' was created');
|
||||
|
||||
if (($user->email) && ($user->activated == '1')) {
|
||||
$data = [
|
||||
'email' => $user->email,
|
||||
'username' => $user->username,
|
||||
'first_name' => $user->first_name,
|
||||
'last_name' => $user->last_name,
|
||||
'password' => $this->tempPassword,
|
||||
];
|
||||
|
||||
if ($this->send_welcome) {
|
||||
$user->notify(new WelcomeNotification($data));
|
||||
}
|
||||
}
|
||||
$user = null;
|
||||
$this->item = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logError($user, 'User');
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an existing department, or create new if it doesn't exist
|
||||
*
|
||||
* @author Daniel Melzter
|
||||
* @since 5.0
|
||||
* @param $department_name string
|
||||
* @return int id of department created/found
|
||||
*/
|
||||
public function createOrFetchDepartment($department_name)
|
||||
{
|
||||
if (is_null($department_name) || $department_name == ''){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
$department = Department::where(['name' => $department_name])->first();
|
||||
if ($department) {
|
||||
$this->log('A matching department ' . $department_name . ' already exists');
|
||||
return $department->id;
|
||||
}
|
||||
|
||||
$department = new department();
|
||||
$department->name = $department_name;
|
||||
$department->user_id = $this->user_id;
|
||||
|
||||
if ($department->save()) {
|
||||
$this->log('department ' . $department_name . ' was created');
|
||||
return $department->id;
|
||||
}
|
||||
|
||||
$this->logError($department, 'Department');
|
||||
return null;
|
||||
}
|
||||
|
||||
public function sendWelcome($send = true)
|
||||
{
|
||||
$this->send_welcome = $send;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user