Merge branch 'develop'

This commit is contained in:
snipe 2018-01-09 20:12:44 -08:00
commit 6245f92e16
32 changed files with 196297 additions and 119 deletions

View file

@ -344,7 +344,7 @@ class AssetsController extends Controller
$asset->model_id = $request->get('model_id'); $asset->model_id = $request->get('model_id');
$asset->order_number = $request->get('order_number'); $asset->order_number = $request->get('order_number');
$asset->notes = $request->get('notes'); $asset->notes = $request->get('notes');
$asset->asset_tag = $request->get('asset_tag'); $asset->asset_tag = $request->get('asset_tag', Asset::autoincrement_asset());
$asset->user_id = Auth::id(); $asset->user_id = Auth::id();
$asset->archived = '0'; $asset->archived = '0';
$asset->physical = '1'; $asset->physical = '1';

View file

@ -36,13 +36,16 @@ class AssetRequest extends Request
'checkin_date' => 'date', 'checkin_date' => 'date',
'supplier_id' => 'integer|nullable', 'supplier_id' => 'integer|nullable',
'status' => 'integer|nullable', 'status' => 'integer|nullable',
'asset_tag' => 'required',
'purchase_cost' => 'numeric|nullable', 'purchase_cost' => 'numeric|nullable',
"assigned_user" => 'sometimes:required_without_all:assigned_asset,assigned_location', "assigned_user" => 'sometimes:required_without_all:assigned_asset,assigned_location',
"assigned_asset" => 'sometimes:required_without_all:assigned_user,assigned_location', "assigned_asset" => 'sometimes:required_without_all:assigned_user,assigned_location',
"assigned_location" => 'sometimes:required_without_all:assigned_user,assigned_asset', "assigned_location" => 'sometimes:required_without_all:assigned_user,assigned_asset',
]; ];
$settings = \App\Models\Setting::getSettings();
$rules['asset_tag'] = ($settings->auto_increment_assets == '1') ? 'max:255' : 'required';
$model = AssetModel::find($this->request->get('model_id')); $model = AssetModel::find($this->request->get('model_id'));
if (($model) && ($model->fieldset)) { if (($model) && ($model->fieldset)) {

View file

@ -26,7 +26,7 @@ class ItemImportRequest extends FormRequest
public function rules() public function rules()
{ {
return [ return [
// 'import-type' => 'required',
]; ];
} }

View file

@ -41,6 +41,7 @@ class AccessoryImporter extends ItemImporter
$this->log("No Matching Accessory, Creating a new one"); $this->log("No Matching Accessory, Creating a new one");
$accessory = new Accessory(); $accessory = new Accessory();
$accessory->fill($this->sanitizeItemForStoring($accessory)); $accessory->fill($this->sanitizeItemForStoring($accessory));
$accessory->unsetEventDispatcher();
if ($accessory->save()) { if ($accessory->save()) {
$accessory->logCreate('Imported using CSV Importer'); $accessory->logCreate('Imported using CSV Importer');
$this->log('Accessory ' . $this->item["name"] . ' was created'); $this->log('Accessory ' . $this->item["name"] . ' was created');

View file

@ -79,28 +79,42 @@ class AssetImporter extends ItemImporter
} }
$this->item['asset_tag'] = $asset_tag; $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); $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"])) { if (isset($this->item["location_id"])) {
$item['rtd_location_id'] = $this->item['location_id']; $item['rtd_location_id'] = $this->item['location_id'];
unset($item['location_id']);
} }
if ($editingAsset) { if ($editingAsset) {
$asset->update($item); $asset->update($item);
} else { } else {
$asset->fill($item); $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)) { if (array_key_exists('custom_fields', $this->item)) {
foreach ($this->item['custom_fields'] as $custom_field => $val) { foreach ($this->item['custom_fields'] as $custom_field => $val) {
$asset->{$custom_field} = $val; $asset->{$custom_field} = $val;
} }
} }
$asset->unsetEventDispatcher();
if ($asset->save()) { if ($asset->save()) {
$asset->logCreate('Imported using csv importer'); $asset->logCreate('Imported using csv importer');
$this->log('Asset ' . $this->item["name"] . ' with serial number ' . $this->item['serial'] . ' was created'); $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; return;
} }
$this->logError($asset, 'Asset "' . $this->item['name'].'"'); $this->logError($asset, 'Asset "' . $this->item['name'].'"');

View file

@ -27,27 +27,26 @@ class ComponentImporter extends ItemImporter
public function createComponentIfNotExists() public function createComponentIfNotExists()
{ {
$component = null; $component = null;
$editingComponent = false;
$this->log("Creating Component"); $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) { if ($component) {
$editingComponent = true; $this->log('A matching Component ' . $this->item["name"] . ' with serial ' .$this->item['serial'].' already exists. ');
$this->log('A matching Component ' . $this->item["name"] . ' already exists. ');
if (!$this->updating) { if (!$this->updating) {
$this->log("Skipping Component"); $this->log("Skipping Component");
return; return;
} }
$this->log("Updating Component"); $this->log("Updating Component");
$component = $this->components[$componentId]; $component->update($this->sanitizeItemForUpdating($component));
$component->update($this->sanitizeItemFor($component));
$component->save(); $component->save();
return; return;
} }
$this->log("No matching component, creating one"); $this->log("No matching component, creating one");
$component = new Component; $component = new Component;
$component->fill($$this->sanitizeItemForStoring($component)); $component->fill($this->sanitizeItemForStoring($component));
$component->unsetEventDispatcher();
if ($component->save()) { if ($component->save()) {
$component->logCreate('Imported using CSV Importer'); $component->logCreate('Imported using CSV Importer');
$this->log("Component " . $this->item["name"] . ' was created'); $this->log("Component " . $this->item["name"] . ' was created');

View file

@ -41,6 +41,7 @@ class ConsumableImporter extends ItemImporter
$consumable = new Consumable(); $consumable = new Consumable();
$consumable->fill($this->sanitizeItemForStoring($consumable)); $consumable->fill($this->sanitizeItemForStoring($consumable));
$consumable->unsetEventDispatcher();
if ($consumable->save()) { if ($consumable->save()) {
$consumable->logCreate('Imported using CSV Importer'); $consumable->logCreate('Imported using CSV Importer');
$this->log("Consumable " . $this->item["name"] . ' was created'); $this->log("Consumable " . $this->item["name"] . ' was created');

View file

@ -239,12 +239,15 @@ abstract class Importer
// A number was given instead of a name // A number was given instead of a name
if (is_numeric($user_name)) { if (is_numeric($user_name)) {
$this->log('User '.$user_name.' is not a name - assume this user already exists'); $this->log('User '.$user_name.' is not a name - assume this user already exists');
$user_username = ''; $user = User::find($user_name);
// No name was given if($user) {
return $user;
}
$this->log('User with id'.$user_name.' does not exist. Continuing through our processes');
} elseif (empty($user_name)) { } elseif (empty($user_name)) {
$this->log('No user data provided - skipping user creation, just adding asset'); $this->log('No user data provided - skipping user creation, just adding asset');
//$user_username = ''; //$user_username = '';
return false;
} else { } else {
$user_email_array = User::generateFormattedNameFromFullName(Setting::getSettings()->email_format, $user_name); $user_email_array = User::generateFormattedNameFromFullName(Setting::getSettings()->email_format, $user_name);
$first_name = $user_email_array['first_name']; $first_name = $user_email_array['first_name'];

View file

@ -67,10 +67,7 @@ class ItemImporter extends Importer
// NO need to call this method if we're running the user import. // NO need to call this method if we're running the user import.
// TODO: Merge these methods. // TODO: Merge these methods.
if(get_class($this) !== UserImporter::class) { if(get_class($this) !== UserImporter::class) {
if ($this->item["user"] = $this->createOrFetchUser($row)) { $this->item["user"] = $this->createOrFetchUser($row);
$this->item['assigned_to'] = $this->item['user']->id;
$this->item['assigned_type'] = User::class;
}
} }
} }

View file

@ -63,6 +63,8 @@ class LicenseImporter extends ItemImporter
} else { } else {
$license->fill($this->sanitizeItemForStoring($license)); $license->fill($this->sanitizeItemForStoring($license));
} }
$license->unsetEventDispatcher();
if ($license->save()) { if ($license->save()) {
$license->logCreate('Imported using csv importer'); $license->logCreate('Imported using csv importer');
$this->log('License ' . $this->item["name"] . ' with serial number ' . $this->item['serial'] . ' was created'); $this->log('License ' . $this->item["name"] . ' with serial number ' . $this->item['serial'] . ' was created');

View file

@ -33,7 +33,7 @@ class UserImporter extends ItemImporter
$this->item['username'] = $this->findCsvMatch($row, 'username'); $this->item['username'] = $this->findCsvMatch($row, 'username');
$this->item['first_name'] = $this->findCsvMatch($row, 'first_name'); $this->item['first_name'] = $this->findCsvMatch($row, 'first_name');
$this->item['last_name'] = $this->findCsvMatch($row, 'last_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['phone'] = $this->findCsvMatch($row, 'phone_number');
$this->item['jobtitle'] = $this->findCsvMatch($row, 'jobtitle'); $this->item['jobtitle'] = $this->findCsvMatch($row, 'jobtitle');
$this->item['employee_num'] = $this->findCsvMatch($row, 'employee_num'); $this->item['employee_num'] = $this->findCsvMatch($row, 'employee_num');

View file

@ -12,6 +12,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Log; use Log;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use DB;
/** /**
* Model for Assets. * Model for Assets.
@ -173,6 +174,10 @@ class Asset extends Depreciable
if ($location != null) { if ($location != null) {
$this->location_id = $location; $this->location_id = $location;
} else {
if($target->location) {
$this->location_id = $target->location->id;
}
} }
if ($this->requireAcceptance()) { if ($this->requireAcceptance()) {
@ -814,7 +819,7 @@ class Asset extends Depreciable
})->orWhere(function ($query) use ($search) { })->orWhere(function ($query) use ($search) {
$query->where('assets_users.first_name', 'LIKE', '%'.$search.'%') $query->where('assets_users.first_name', 'LIKE', '%'.$search.'%')
->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%') ->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%')
->orWhereRaw('CONCAT(assets_users.first_name," ",assets_users.last_name) LIKE ?', ["%$search%", "%$search%"]) ->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$search%", "%$search%"])
->orWhere('assets_users.username', 'LIKE', '%'.$search.'%') ->orWhere('assets_users.username', 'LIKE', '%'.$search.'%')
->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%') ->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%')
->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%'); ->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%');
@ -873,7 +878,7 @@ class Asset extends Depreciable
})->orWhere(function ($query) use ($search) { })->orWhere(function ($query) use ($search) {
$query->where('assets_users.first_name', 'LIKE', '%'.$search.'%') $query->where('assets_users.first_name', 'LIKE', '%'.$search.'%')
->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%') ->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%')
->orWhereRaw('CONCAT(assets_users.first_name," ",assets_users.last_name) LIKE ?', ["%$search%", "%$search%"]) ->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$search%", "%$search%"])
->orWhere('assets_users.username', 'LIKE', '%'.$search.'%') ->orWhere('assets_users.username', 'LIKE', '%'.$search.'%')
->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%') ->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%')
->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%'); ->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%');

View file

@ -55,6 +55,7 @@ class Component extends SnipeModel
'purchase_date', 'purchase_date',
'min_amt', 'min_amt',
'qty', 'qty',
'serial'
]; ];
public function location() public function location()

View file

@ -182,7 +182,7 @@ trait Loggable
$log->location_id = null; $log->location_id = null;
$log->note = $note; $log->note = $note;
$log->user_id = $user_id; $log->user_id = $user_id;
$log->logaction('created'); $log->logaction('create');
$log->save(); $log->save();
return $log; return $log;
} }

View file

@ -14,9 +14,10 @@
"babel-preset-latest": "^6.24.1", "babel-preset-latest": "^6.24.1",
"cross-env": "^5.0.5", "cross-env": "^5.0.5",
"jquery": "^3.1.1", "jquery": "^3.1.1",
"laravel-mix": "1.4.3", "laravel-mix": "1.7",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"vue": "2.4.4", "vue": "2.4.4",
"vue-loader": "^13.6.1",
"vue-template-compiler": "2.4.4" "vue-template-compiler": "2.4.4"
}, },
"dependencies": { "dependencies": {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4387
public/css/dist/all.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

61561
public/js/dist/all.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,14 +1,10 @@
{ {
"/js/build/vue.js": "/js/build/vue.js?id=e6804371942215bd1d7d", "/js/build/vue.js": "/js/build/vue.js?id=32ce13a589cb455849de",
"/css/AdminLTE.css": "/css/AdminLTE.css?id=b8be19a285eaf44eec37", "/css/AdminLTE.css": "/css/AdminLTE.css?id=889dc040f2ddfca6efde",
"/css/app.css": "/css/app.css?id=407edb63cc6b6dc62405", "/css/app.css": "/css/app.css?id=3a1e8c168fa8714043a6",
"/css/overrides.css": "/css/overrides.css?id=1bdafb06a8609780f546", "/css/overrides.css": "/css/overrides.css?id=21c1a4ba652c6546f14b",
"/js/build/vue.js.map": "/js/build/vue.js.map?id=3b3d417664a61dcce3e9", "/css/dist/all.css": "/css/dist/all.css?id=9bf6e85e322473238339",
"/css/AdminLTE.css.map": "/css/AdminLTE.css.map?id=99f5a5a03c4155cf69f6", "/js/dist/all.js": "/js/dist/all.js?id=254a99c7a1ccaa032f2f",
"/css/app.css.map": "/css/app.css.map?id=bdbe05e6ecd70ccfac72", "/css/build/all.css": "/css/build/all.css?id=9bf6e85e322473238339",
"/css/overrides.css.map": "/css/overrides.css.map?id=898c91d4a425b01b589b", "/js/build/all.js": "/js/build/all.js?id=254a99c7a1ccaa032f2f"
"/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"
} }

View file

@ -13,7 +13,7 @@ tr {
<label for="import-type">Import Type:</label> <label for="import-type">Import Type:</label>
</div> </div>
<div class="col-md-4 col-xs-12"> <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> <option disabled value="0"></option>
</select2> </select2>
</div> </div>
@ -60,7 +60,14 @@ tr {
<td> <td>
<button type="button" class="btn btn-sm btn-default" @click="processDetail = false">Cancel</button> <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> <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> </td>
</tr> </tr>
</template> </template>
@ -73,6 +80,7 @@ tr {
activeFile: this.file, activeFile: this.file,
processDetail: false, processDetail: false,
statusText: null, statusText: null,
statusType: null,
options: { options: {
importType: this.file.import_type, importType: this.file.import_type,
update: false, update: false,
@ -151,10 +159,33 @@ tr {
return this.columnOptions.general.concat(this.columnOptions.users); return this.columnOptions.general.concat(this.columnOptions.users);
} }
return this.columnOptions.general; 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: { methods: {
postSave() { 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.statusText = "Processing...";
this.$http.post(route('api.imports.importFile', this.file.id), { this.$http.post(route('api.imports.importFile', this.file.id), {
'import-update': this.options.update, 'import-update': this.options.update,
@ -162,12 +193,14 @@ tr {
'column-mappings': this.columnMappings 'column-mappings': this.columnMappings
}).then( ({body}) => { }).then( ({body}) => {
// Success // Success
this.statusType="success";
this.statusText = "Success... Redirecting."; this.statusText = "Success... Redirecting.";
window.location.href = body.messages.redirect_url; window.location.href = body.messages.redirect_url;
}, ({body}) => { }, ({body}) => {
// Failure // Failure
if(body.status == 'import-errors') { if(body.status == 'import-errors') {
window.eventHub.$emit('importErrors', body.messages); window.eventHub.$emit('importErrors', body.messages);
this.statusType='error';
this.statusText = "Error"; this.statusText = "Error";
} else { } else {
this.$emit('alert', { this.$emit('alert', {
@ -188,7 +221,9 @@ tr {
// Then, for any values that have a likely match, we make that active. // Then, for any values that have a likely match, we make that active.
for(var j=0; j < this.columns.length; j++) { for(var j=0; j < this.columns.length; j++) {
let column = this.columns[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) { if(index != -1) {
this.$set(this.columnMappings, this.file.header_row[index], column.id) this.$set(this.columnMappings, this.file.header_row[index], column.id)
} }

View file

@ -712,7 +712,7 @@
</td> </td>
<td> <td>
@can('update', \App\Models\Asset::class) @can('update', \App\Models\Asset::class)
<a class="btn delete-asset btn-danger btn-sm" href="{{ route('delete/assetfile', [$asset->id, $file->id]) }}"><i class="fa fa-trash icon-white"></i></a> <a class="btn delete-asset btn-danger btn-sm" href="{{ route('delete/assetfile', [$asset->id, $file->id]) }}" data-tooltip="true" data-title="Delete" data-content="Are you sure you wish to delete {{$file->filename}}"><i class="fa fa-trash icon-white"></i></a>
@endcan @endcan
</td> </td>
</tr> </tr>

View file

@ -166,6 +166,13 @@
</li> </li>
@endif @endif
@if ($model->notes)
<li>
{{ trans('general.notes') }}:
{{ $model->notes }}
</li>
@endif
@if ($model->deleted_at!='') @if ($model->deleted_at!='')

View file

@ -3,9 +3,12 @@
<div class="col-md-5"> <div class="col-md-5">
<label class="btn btn-default"> <label class="btn btn-default">
{{ trans('button.select_file') }} {{ trans('button.select_file') }}
<input type="file" name="image" accept="image/gif,image/jpeg,image/png,image/svg" hidden> <input type="file" name="image" accept="image/gif,image/jpeg,image/png,image/svg"
onchange="$('#upload-file-info').html(this.files[0].name)" style="display:none">
</label> </label>
<span class='label label-default' id="upload-file-info"></span>
<p class="help-block">{{ trans('general.image_filetypes_help') }}</p> <p class="help-block">{{ trans('general.image_filetypes_help') }}</p>
{!! $errors->first('image', '<span class="alert-msg">:message</span>') !!} {!! $errors->first('image', '<span class="alert-msg">:message</span>') !!}
</div> </div>
</div> </div>

View file

@ -35,7 +35,7 @@ mix
).sourceMaps() ).sourceMaps()
.scripts([ .scripts([
'./node_modules/jquery-ui/jquery-ui.js', './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/tether/dist/js/tether.min.js',
'./node_modules/jquery-slimscroll/jquery.slimscroll.js', './node_modules/jquery-slimscroll/jquery.slimscroll.js',
'./node_modules/jquery.iframe-transport/jquery.iframe-transport.js', './node_modules/jquery.iframe-transport/jquery.iframe-transport.js',