mirror of
https://github.com/snipe/snipe-it.git
synced 2024-11-09 23:24:06 -08:00
Importer again (#4702)
* If a user id is provided in the name column of an import, we should assume that it is a user id and check out to it. * Fix build of vue files. The location is public/js/build, not public/build * Ensure a status type is set before allowing submission of an import. Also expand the status text label to change color based on success/failure. Fixes #4658 * Use right key to lookup emails when importing users. Fixes 4619. * Import serial for components, and make unique matches based on the serial as well as the name. Fixes #4569 * Set the location_id when importing an item properly. This moves as well to using the Asset::checkout() method, which should consolidate the logic into a useful spot. Fixes #4563 (I think) * Production assets. * Case insensitive field map guessing and repopulate when changingin import type.
This commit is contained in:
parent
1bd7392531
commit
f16ce09a7a
|
@ -26,7 +26,7 @@ class ItemImportRequest extends FormRequest
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
//
|
||||
'import-type' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -79,20 +79,28 @@ class AssetImporter extends ItemImporter
|
|||
}
|
||||
|
||||
$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('user', $this->item)) {
|
||||
$user = $this->item['user'];
|
||||
}
|
||||
$item = $this->sanitizeItemForStoring($asset, $editingAsset);
|
||||
// By default we're set this to location_id in the item.
|
||||
// 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'];
|
||||
unset($item['location_id']);
|
||||
}
|
||||
|
||||
|
||||
if ($editingAsset) {
|
||||
$asset->update($item);
|
||||
} else {
|
||||
$asset->fill($item);
|
||||
}
|
||||
// If we're updating, we don't want to overwrite old fields.
|
||||
|
||||
// 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;
|
||||
|
@ -101,6 +109,11 @@ class AssetImporter extends ItemImporter
|
|||
if ($asset->save()) {
|
||||
$asset->logCreate('Imported using csv importer');
|
||||
$this->log('Asset ' . $this->item["name"] . ' with serial number ' . $this->item['serial'] . ' was created');
|
||||
|
||||
// If we have a user to checkout to, lets do so.
|
||||
if(isset($user)) {
|
||||
$asset->fresh()->checkOut($user);
|
||||
}
|
||||
return;
|
||||
}
|
||||
$this->logError($asset, 'Asset "' . $this->item['name'].'"');
|
||||
|
|
|
@ -29,11 +29,13 @@ class ComponentImporter extends ItemImporter
|
|||
$component = null;
|
||||
$editingComponent = false;
|
||||
$this->log("Creating Component");
|
||||
$component = Component::where('name', $this->item['name']);
|
||||
$component = Component::where('name', $this->item['name'])
|
||||
->where('serial', $this->item['serial'])
|
||||
->first();
|
||||
|
||||
if ($component) {
|
||||
$editingComponent = true;
|
||||
$this->log('A matching Component ' . $this->item["name"] . ' already exists. ');
|
||||
$this->log('A matching Component ' . $this->item["name"] . ' with serial ' .$this->item['serial'].' already exists. ');
|
||||
if (!$this->updating) {
|
||||
$this->log("Skipping Component");
|
||||
return;
|
||||
|
|
|
@ -239,12 +239,15 @@ abstract class Importer
|
|||
// A number was given instead of a name
|
||||
if (is_numeric($user_name)) {
|
||||
$this->log('User '.$user_name.' is not a name - assume this user already exists');
|
||||
$user_username = '';
|
||||
// No name was given
|
||||
$user = User::find($user_name);
|
||||
if($user) {
|
||||
return $user;
|
||||
}
|
||||
$this->log('User with id'.$user_name.' does not exist. Continuing through our processes');
|
||||
} elseif (empty($user_name)) {
|
||||
|
||||
$this->log('No user data provided - skipping user creation, just adding asset');
|
||||
//$user_username = '';
|
||||
return false;
|
||||
} else {
|
||||
$user_email_array = User::generateFormattedNameFromFullName(Setting::getSettings()->email_format, $user_name);
|
||||
$first_name = $user_email_array['first_name'];
|
||||
|
|
|
@ -67,10 +67,7 @@ class ItemImporter extends Importer
|
|||
// NO need to call this method if we're running the user import.
|
||||
// TODO: Merge these methods.
|
||||
if(get_class($this) !== UserImporter::class) {
|
||||
if ($this->item["user"] = $this->createOrFetchUser($row)) {
|
||||
$this->item['assigned_to'] = $this->item['user']->id;
|
||||
$this->item['assigned_type'] = User::class;
|
||||
}
|
||||
$this->item["user"] = $this->createOrFetchUser($row);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ class UserImporter extends ItemImporter
|
|||
$this->item['username'] = $this->findCsvMatch($row, 'username');
|
||||
$this->item['first_name'] = $this->findCsvMatch($row, 'first_name');
|
||||
$this->item['last_name'] = $this->findCsvMatch($row, 'last_name');
|
||||
$this->item['email'] = $this->findCsvMatch($row, 'user_email');
|
||||
$this->item['email'] = $this->findCsvMatch($row, 'email');
|
||||
$this->item['phone'] = $this->findCsvMatch($row, 'phone_number');
|
||||
$this->item['jobtitle'] = $this->findCsvMatch($row, 'jobtitle');
|
||||
$this->item['employee_num'] = $this->findCsvMatch($row, 'employee_num');
|
||||
|
|
|
@ -173,6 +173,10 @@ class Asset extends Depreciable
|
|||
|
||||
if ($location != null) {
|
||||
$this->location_id = $location;
|
||||
} else {
|
||||
if($target->location) {
|
||||
$this->location_id = $target->location->id;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->requireAcceptance()) {
|
||||
|
|
|
@ -55,6 +55,7 @@ class Component extends SnipeModel
|
|||
'purchase_date',
|
||||
'min_amt',
|
||||
'qty',
|
||||
'serial'
|
||||
];
|
||||
|
||||
public function location()
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
"babel-preset-latest": "^6.24.1",
|
||||
"cross-env": "^5.0.5",
|
||||
"jquery": "^3.1.1",
|
||||
"laravel-mix": "1.4.3",
|
||||
"laravel-mix": "1.7",
|
||||
"lodash": "^4.17.4",
|
||||
"vue": "2.4.4",
|
||||
"vue-loader": "^13.6.1",
|
||||
"vue-template-compiler": "2.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/css/dist/all.css
vendored
BIN
public/css/dist/all.css
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/js/dist/all.js
vendored
BIN
public/js/dist/all.js
vendored
Binary file not shown.
|
@ -1,14 +1,10 @@
|
|||
{
|
||||
"/js/build/vue.js": "/js/build/vue.js?id=e6804371942215bd1d7d",
|
||||
"/css/AdminLTE.css": "/css/AdminLTE.css?id=b8be19a285eaf44eec37",
|
||||
"/css/app.css": "/css/app.css?id=407edb63cc6b6dc62405",
|
||||
"/css/overrides.css": "/css/overrides.css?id=1bdafb06a8609780f546",
|
||||
"/js/build/vue.js.map": "/js/build/vue.js.map?id=3b3d417664a61dcce3e9",
|
||||
"/css/AdminLTE.css.map": "/css/AdminLTE.css.map?id=99f5a5a03c4155cf69f6",
|
||||
"/css/app.css.map": "/css/app.css.map?id=bdbe05e6ecd70ccfac72",
|
||||
"/css/overrides.css.map": "/css/overrides.css.map?id=898c91d4a425b01b589b",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=3a8aa974e7b09b52b18c",
|
||||
"/js/dist/all.js": "/js/dist/all.js?id=88f08e0103b14f7949b3",
|
||||
"/css/build/all.css": "/css/build/all.css?id=3a8aa974e7b09b52b18c",
|
||||
"/js/build/all.js": "/js/build/all.js?id=88f08e0103b14f7949b3"
|
||||
"/js/build/vue.js": "/js/build/vue.js?id=32ce13a589cb455849de",
|
||||
"/css/AdminLTE.css": "/css/AdminLTE.css?id=889dc040f2ddfca6efde",
|
||||
"/css/app.css": "/css/app.css?id=3a1e8c168fa8714043a6",
|
||||
"/css/overrides.css": "/css/overrides.css?id=21c1a4ba652c6546f14b",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=9bf6e85e322473238339",
|
||||
"/js/dist/all.js": "/js/dist/all.js?id=254a99c7a1ccaa032f2f",
|
||||
"/css/build/all.css": "/css/build/all.css?id=9bf6e85e322473238339",
|
||||
"/js/build/all.js": "/js/build/all.js?id=254a99c7a1ccaa032f2f"
|
||||
}
|
|
@ -13,7 +13,7 @@ tr {
|
|||
<label for="import-type">Import Type:</label>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-12">
|
||||
<select2 :options="options.importTypes" v-model="options.importType">
|
||||
<select2 :options="options.importTypes" v-model="options.importType" required>
|
||||
<option disabled value="0"></option>
|
||||
</select2>
|
||||
</div>
|
||||
|
@ -60,7 +60,14 @@ tr {
|
|||
<td>
|
||||
<button type="button" class="btn btn-sm btn-default" @click="processDetail = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-sm btn-primary" @click="postSave">Import</button>
|
||||
<div class="alert alert-success col-md-5 col-md-offset-1" style="text-align:left" v-if="statusText">{{ this.statusText }}</div>
|
||||
<div
|
||||
class="alert col-md-5 col-md-offset-1"
|
||||
:class="alertClass"
|
||||
style="text-align:left"
|
||||
v-if="statusText"
|
||||
>
|
||||
{{ this.statusText }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
@ -73,6 +80,7 @@ tr {
|
|||
activeFile: this.file,
|
||||
processDetail: false,
|
||||
statusText: null,
|
||||
statusType: null,
|
||||
options: {
|
||||
importType: this.file.import_type,
|
||||
update: false,
|
||||
|
@ -151,10 +159,33 @@ tr {
|
|||
return this.columnOptions.general.concat(this.columnOptions.users);
|
||||
}
|
||||
return this.columnOptions.general;
|
||||
},
|
||||
alertClass() {
|
||||
if(this.statusType=='success') {
|
||||
return 'alert-success';
|
||||
}
|
||||
if(this.statusType=='error') {
|
||||
return 'alert-danger';
|
||||
}
|
||||
return 'alert-info';
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
columns() {
|
||||
console.log("CHANGED");
|
||||
this.populateSelect2ActiveItems();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
postSave() {
|
||||
console.log('saving');
|
||||
console.log(this.options.importType);
|
||||
if(!this.options.importType) {
|
||||
this.statusType='error';
|
||||
this.statusText= "An import type is required... ";
|
||||
return;
|
||||
}
|
||||
this.statusType='pending';
|
||||
this.statusText = "Processing...";
|
||||
this.$http.post(route('api.imports.importFile', this.file.id), {
|
||||
'import-update': this.options.update,
|
||||
|
@ -162,12 +193,14 @@ tr {
|
|||
'column-mappings': this.columnMappings
|
||||
}).then( ({body}) => {
|
||||
// Success
|
||||
this.statusType="success";
|
||||
this.statusText = "Success... Redirecting.";
|
||||
window.location.href = body.messages.redirect_url;
|
||||
}, ({body}) => {
|
||||
// Failure
|
||||
if(body.status == 'import-errors') {
|
||||
window.eventHub.$emit('importErrors', body.messages);
|
||||
this.statusType='error';
|
||||
this.statusText = "Error";
|
||||
} else {
|
||||
this.$emit('alert', {
|
||||
|
@ -188,7 +221,9 @@ tr {
|
|||
// Then, for any values that have a likely match, we make that active.
|
||||
for(var j=0; j < this.columns.length; j++) {
|
||||
let column = this.columns[j];
|
||||
let index = this.file.header_row.indexOf(column.text)
|
||||
let lower = this.file.header_row.map((value) => value.toLowerCase());
|
||||
console.dir(lower);
|
||||
let index = lower.indexOf(column.text.toLowerCase())
|
||||
if(index != -1) {
|
||||
this.$set(this.columnMappings, this.file.header_row[index], column.id)
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ mix
|
|||
).sourceMaps()
|
||||
.scripts([
|
||||
'./node_modules/jquery-ui/jquery-ui.js',
|
||||
'./public/build/vue.js', //this is the modularized nifty Vue.js thing we just built, above!
|
||||
'./public/js/build/vue.js', //this is the modularized nifty Vue.js thing we just built, above!
|
||||
'./node_modules/tether/dist/js/tether.min.js',
|
||||
'./node_modules/jquery-slimscroll/jquery.slimscroll.js',
|
||||
'./node_modules/jquery.iframe-transport/jquery.iframe-transport.js',
|
||||
|
|
Loading…
Reference in a new issue