Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c651c9f1ed | ||
|
|
7c390cee2c | ||
|
|
987536930c | ||
|
|
10f322198f | ||
|
|
761371509d | ||
|
|
3518ea7e7d | ||
|
|
c92eed2b3e | ||
|
|
0054ce3071 | ||
|
|
b0f74466bb | ||
|
|
b4a0484295 | ||
|
|
bb874012d9 | ||
|
|
bb8583eb14 | ||
|
|
8d2c229bc3 | ||
|
|
48e6208214 | ||
|
|
22233e3ba6 | ||
|
|
e439f15a64 | ||
|
|
42175782a5 | ||
|
|
c7a21e0e4d | ||
|
|
d98ffd94f9 | ||
|
|
6ad5da44f3 | ||
|
|
479f422e68 | ||
|
|
e10cdd57a5 | ||
|
|
bf157773c8 | ||
|
|
fba3949530 | ||
|
|
abc3dea8ac | ||
|
|
51d74ac06d | ||
|
|
af835d6efc |
64
app/Console/Commands/SendExpectedCheckinAlerts.php
Normal file
64
app/Console/Commands/SendExpectedCheckinAlerts.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Notifications\ExpectedCheckinNotification;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class SendExpectedCheckinAlerts extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'snipeit:expected-checkin';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Check for overdue or upcoming expected checkins.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function fire()
|
||||
{
|
||||
|
||||
$whenNotify = Carbon::now()->addDays(7);
|
||||
$assets = Asset::with('assignedTo')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get();
|
||||
|
||||
$this->info($whenNotify.' is deadline');
|
||||
$this->info($assets->count().' assets');
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
if ($asset->assignedTo && $asset->checkoutOutToUser()) {
|
||||
$asset->assignedTo->notify((new ExpectedCheckinNotification($asset)));
|
||||
//$this->info($asset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ class Kernel extends ConsoleKernel
|
||||
Commands\CreateAdmin::class,
|
||||
Commands\SendExpirationAlerts::class,
|
||||
Commands\SendInventoryAlerts::class,
|
||||
Commands\SendExpectedCheckinAlerts::class,
|
||||
Commands\ObjectImportCommand::class,
|
||||
Commands\Versioning::class,
|
||||
Commands\SystemBackup::class,
|
||||
@@ -38,6 +39,7 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
$schedule->command('snipeit:inventory-alerts')->daily();
|
||||
$schedule->command('snipeit:expiring-alerts')->daily();
|
||||
$schedule->command('snipeit:expected-checkins')->daily();
|
||||
$schedule->command('snipeit:backup')->weekly();
|
||||
$schedule->command('backup:clean')->daily();
|
||||
}
|
||||
|
||||
12
app/Exceptions/CheckoutNotAllowed.php
Normal file
12
app/Exceptions/CheckoutNotAllowed.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
class CheckoutNotAllowed extends Exception
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
"A checkout is not allowed under these circumstances";
|
||||
}
|
||||
}
|
||||
@@ -260,7 +260,7 @@ class AccessoriesController extends Controller
|
||||
'assigned_to' => $request->get('assigned_to')
|
||||
]);
|
||||
|
||||
$logaction = $accessory->logCheckout(e(Input::get('note')));
|
||||
$logaction = $accessory->logCheckout(e(Input::get('note')), $user);
|
||||
|
||||
DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first();
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\AssetMaintenance;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Company;
|
||||
use App\Models\Asset;
|
||||
use App\Helpers\Helper;
|
||||
use Auth;
|
||||
use Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Transformers\AssetMaintenancesTransformer;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\Company;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Asset Maintenance for
|
||||
|
||||
@@ -84,9 +84,8 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
$assets = Company::scopeCompanyables(Asset::select('assets.*'))->with(
|
||||
'assetLoc', 'assetstatus', 'defaultLoc', 'assetlog', 'company',
|
||||
'model.category', 'model.manufacturer', 'model.fieldset', 'assigneduser','supplier');
|
||||
|
||||
'assetloc', 'assetstatus', 'defaultLoc', 'assetlog', 'company',
|
||||
'model.category', 'model.manufacturer', 'model.fieldset','supplier');
|
||||
// If we should search on everything
|
||||
if (($request->has('search')) && (count($filter) == 0)) {
|
||||
$assets->TextSearch($request->input('search'));
|
||||
@@ -97,7 +96,6 @@ class AssetsController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// These are used by the API to query against specific ID numbers
|
||||
if ($request->has('status_id')) {
|
||||
$assets->where('status_id', '=', $request->input('status_id'));
|
||||
@@ -507,23 +505,41 @@ class AssetsController extends Controller
|
||||
* @since [v4.0]
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function audit(Request $request, $id) {
|
||||
public function audit(Request $request) {
|
||||
|
||||
|
||||
$this->authorize('audit', Asset::class);
|
||||
|
||||
$rules = array(
|
||||
'id' => 'required'
|
||||
'asset_tag' => 'required',
|
||||
'location_id' => 'exists:locations,id|nullable|numeric',
|
||||
'next_audit_date' => 'date|nullable'
|
||||
);
|
||||
|
||||
$validator = \Validator::make($request->all(), $rules);
|
||||
|
||||
$asset = Asset::findOrFail($id);
|
||||
$asset->next_audit_date = $request->input('next_audit_date');
|
||||
|
||||
if ($asset->save()) {
|
||||
$asset->logAudit(request('note'));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.audit.success')));
|
||||
$validator = Validator::make($request->all(), $rules);
|
||||
if ($validator->fails()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
|
||||
}
|
||||
|
||||
$asset = Asset::where('asset_tag','=', $request->input('asset_tag'))->first();
|
||||
|
||||
|
||||
if ($asset) {
|
||||
$asset->next_audit_date = $request->input('next_audit_date');
|
||||
if ($asset->save()) {
|
||||
$log = $asset->logAudit(request('note'),request('location_id'));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', [
|
||||
'asset_tag'=> e($asset->asset_tag),
|
||||
'note'=> e($request->input('note')),
|
||||
'next_audit_date' => Helper::getFormattedDateObject($log->calcNextAuditDate())
|
||||
], trans('admin/hardware/message.audit.success')));
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', ['asset_tag'=> e($request->input('asset_tag'))], 'Asset with tag '.$request->input('asset_tag').' not found'));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,4 +148,47 @@ class ConsumablesController extends Controller
|
||||
$consumable->delete();
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.delete.success')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON response containing details on the users associated with this consumable.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @see ConsumablesController::getView() method that returns the form.
|
||||
* @since [v1.0]
|
||||
* @param int $consumableId
|
||||
* @return array
|
||||
*/
|
||||
public function getDataView($consumableId)
|
||||
{
|
||||
//$consumable = Consumable::find($consumableID);
|
||||
$consumable = Consumable::with(array('consumableAssignments'=>
|
||||
function ($query) {
|
||||
$query->orderBy('created_at', 'DESC');
|
||||
},
|
||||
'consumableAssignments.admin'=> function ($query) {
|
||||
},
|
||||
'consumableAssignments.user'=> function ($query) {
|
||||
},
|
||||
))->find($consumableId);
|
||||
|
||||
// $consumable->load('consumableAssignments.admin','consumableAssignments.user');
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($consumable)) {
|
||||
return ['total' => 0, 'rows' => []];
|
||||
}
|
||||
$this->authorize('view', Component::class);
|
||||
$rows = array();
|
||||
|
||||
foreach ($consumable->consumableAssignments as $consumable_assignment) {
|
||||
$rows[] = [
|
||||
'name' => $consumable_assignment->user->present()->nameUrl(),
|
||||
'created_at' => ($consumable_assignment->created_at->format('Y-m-d H:i:s')=='-0001-11-30 00:00:00') ? '' : $consumable_assignment->created_at->format('Y-m-d H:i:s'),
|
||||
'admin' => ($consumable_assignment->admin) ? $consumable_assignment->admin->present()->nameUrl() : '',
|
||||
];
|
||||
}
|
||||
|
||||
$consumableCount = $consumable->users->count();
|
||||
$data = array('total' => $consumableCount, 'rows' => $rows);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class LicensesController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view', License::class);
|
||||
$licenses = Company::scopeCompanyables(License::with('company', 'licenseSeatsRelation', 'manufacturer'));
|
||||
$licenses = Company::scopeCompanyables(License::with('company', 'licenseSeatsRelation', 'manufacturer', 'supplier'));
|
||||
|
||||
if ($request->has('search')) {
|
||||
$licenses = $licenses->TextSearch($request->input('search'));
|
||||
|
||||
@@ -19,7 +19,7 @@ class ReportsController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
|
||||
$actionlogs = Actionlog::with('item', 'user', 'target');
|
||||
$actionlogs = Actionlog::with('item', 'user', 'target','location');
|
||||
|
||||
if ($request->has('search')) {
|
||||
$actionlogs = $actionlogs->TextSearch(e($request->input('search')));
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Requests\SaveUserRequest;
|
||||
use App\Models\Asset;
|
||||
|
||||
class UsersController extends Controller
|
||||
{
|
||||
@@ -182,4 +183,19 @@ class UsersController extends Controller
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON containing a list of assets assigned to a user.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @param $userId
|
||||
* @return string JSON
|
||||
*/
|
||||
public function assets($id)
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
$assets = Asset::where('assigned_to', '=', $id)->with('model')->get();
|
||||
return response()->json($assets);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,17 +537,18 @@ class AssetsController extends Controller
|
||||
$this->authorize('checkin', $asset);
|
||||
|
||||
$admin = Auth::user();
|
||||
$user = $asset->assignedUser;
|
||||
if($asset->assignedType() == Asset::USER) {
|
||||
$user = $asset->assignedTo;
|
||||
}
|
||||
if (is_null($target = $asset->assignedTo)) {
|
||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
|
||||
}
|
||||
|
||||
// This is just used for the redirect
|
||||
$return_to = $asset->assigned_to;
|
||||
$asset->expected_checkin = null;
|
||||
$asset->last_checkout = null;
|
||||
$asset->assigned_to = null;
|
||||
$asset->assignedTo()->disassociate($asset);
|
||||
$asset->assigned_type = null;
|
||||
$asset->accepted = null;
|
||||
$asset->name = e(Input::get('name'));
|
||||
|
||||
@@ -566,7 +567,7 @@ class AssetsController extends Controller
|
||||
$data['item_serial'] = $asset->serial;
|
||||
$data['note'] = $logaction->note;
|
||||
|
||||
if ((($asset->checkin_email()=='1')) && (isset($user)) && (!config('app.lock_passwords'))) {
|
||||
if ((($asset->checkin_email()=='1')) && (isset($user)) && (!empty($user->email)) && (!config('app.lock_passwords'))) {
|
||||
Mail::send('emails.checkin-asset', $data, function ($m) use ($user) {
|
||||
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
|
||||
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
|
||||
@@ -575,7 +576,7 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
if ($backto=='user') {
|
||||
return redirect()->to("admin/users/".$return_to.'/view')->with('success', trans('admin/hardware/message.checkin.success'));
|
||||
return redirect()->to("admin/users/".$user->id.'/view')->with('success', trans('admin/hardware/message.checkin.success'));
|
||||
}
|
||||
return redirect()->route("hardware.index")->with('success', trans('admin/hardware/message.checkin.success'));
|
||||
}
|
||||
@@ -957,7 +958,7 @@ class AssetsController extends Controller
|
||||
* @since [v1.0]
|
||||
* @return View
|
||||
*/
|
||||
public function getDeleteFile($assetId = null, $fileId = null)
|
||||
public function deleteFile($assetId = null, $fileId = null)
|
||||
{
|
||||
$asset = Asset::find($assetId);
|
||||
$this->authorize('update', $asset);
|
||||
@@ -1238,25 +1239,43 @@ class AssetsController extends Controller
|
||||
return redirect()->to("hardware/bulk-checkout")->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($errors);
|
||||
}
|
||||
|
||||
|
||||
public function quickScan(Request $request)
|
||||
{
|
||||
$this->authorize('audit', Asset::class);
|
||||
$dt = Carbon::now()->addMonths(12)->toDateString();
|
||||
return view('hardware/quickscan')->with('next_audit_date', $dt)->with('locations_list', Helper::locationsList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function audit(Request $request, $id)
|
||||
{
|
||||
$this->authorize('audit', Asset::class);
|
||||
|
||||
$dt = Carbon::now()->addMonths(12)->toDateString();
|
||||
|
||||
$asset = Asset::findOrFail($id);
|
||||
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt);
|
||||
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list', Helper::locationsList());
|
||||
}
|
||||
|
||||
public function auditStore(Request $request, $id)
|
||||
{
|
||||
$this->authorize('audit', Asset::class);
|
||||
|
||||
$rules = array(
|
||||
'location_id' => 'exists:locations,id|nullable|numeric',
|
||||
'next_audit_date' => 'date|nullable'
|
||||
);
|
||||
|
||||
$validator = \Validator::make($request->all(), $rules);
|
||||
if ($validator->fails()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
|
||||
}
|
||||
|
||||
$asset = Asset::findOrFail($id);
|
||||
$asset->next_audit_date = $request->input('next_audit_date');
|
||||
|
||||
if ($asset->save()) {
|
||||
$asset->logAudit(request('note'));
|
||||
$asset->logAudit(request('note'),request('location_id'));
|
||||
return redirect()->to("hardware")->with('success', trans('admin/hardware/message.audit.success'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ class ComponentsController extends Controller
|
||||
'asset_id' => $asset_id
|
||||
]);
|
||||
|
||||
$component->logCheckout(e(Input::get('note')), $asset_id);
|
||||
$component->logCheckout(e(Input::get('note')), $asset);
|
||||
return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success'));
|
||||
}
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ class ConsumablesController extends Controller
|
||||
'assigned_to' => e(Input::get('assigned_to'))
|
||||
]);
|
||||
|
||||
$logaction = $consumable->logCheckout(e(Input::get('note')));
|
||||
$logaction = $consumable->logCheckout(e(Input::get('note')), $user);
|
||||
$data['log_id'] = $logaction->id;
|
||||
$data['eula'] = $consumable->getEula();
|
||||
$data['first_name'] = $user->first_name;
|
||||
@@ -273,47 +273,4 @@ class ConsumablesController extends Controller
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a JSON response containing details on the users associated with this consumable.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @see ConsumablesController::getView() method that returns the form.
|
||||
* @since [v1.0]
|
||||
* @param int $consumableId
|
||||
* @return array
|
||||
*/
|
||||
public function getDataView($consumableId)
|
||||
{
|
||||
//$consumable = Consumable::find($consumableID);
|
||||
$consumable = Consumable::with(array('consumableAssigments'=>
|
||||
function ($query) {
|
||||
$query->orderBy('created_at', 'DESC');
|
||||
},
|
||||
'consumableAssigments.admin'=> function ($query) {
|
||||
},
|
||||
'consumableAssigments.user'=> function ($query) {
|
||||
},
|
||||
))->find($consumableId);
|
||||
|
||||
// $consumable->load('consumableAssigments.admin','consumableAssigments.user');
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($consumable)) {
|
||||
return ['total' => 0, 'rows' => []];
|
||||
}
|
||||
$this->authorize('view', Component::class);
|
||||
$rows = array();
|
||||
|
||||
foreach ($consumable->consumableAssigments as $consumable_assignment) {
|
||||
$rows[] = [
|
||||
'name' => $consumable_assignment->user->present()->nameUrl(),
|
||||
'created_at' => ($consumable_assignment->created_at->format('Y-m-d H:i:s')=='-0001-11-30 00:00:00') ? '' : $consumable_assignment->created_at->format('Y-m-d H:i:s'),
|
||||
'admin' => ($consumable_assignment->admin) ? $consumable_assignment->admin->present()->nameUrl() : '',
|
||||
];
|
||||
}
|
||||
|
||||
$consumableCount = $consumable->users->count();
|
||||
$data = array('total' => $consumableCount, 'rows' => $rows);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,22 +291,22 @@ class LicensesController extends Controller
|
||||
// Ooops.. something went wrong
|
||||
return redirect()->back()->withInput()->withErrors($validator);
|
||||
}
|
||||
|
||||
$target = null;
|
||||
if ($assigned_to!='') {
|
||||
// Check if the user exists
|
||||
if (is_null($is_assigned_to = User::find($assigned_to))) {
|
||||
if (is_null($target = User::find($assigned_to))) {
|
||||
// Redirect to the asset management page with error
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.user_does_not_exist'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($asset_id!='') {
|
||||
if (is_null($asset = Asset::find($asset_id))) {
|
||||
if (is_null($target = Asset::find($asset_id))) {
|
||||
// Redirect to the asset management page with error
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.asset_does_not_exist'));
|
||||
}
|
||||
|
||||
if (($asset->assigned_to!='') && (($asset->assigned_to!=$assigned_to)) && ($assigned_to!='')) {
|
||||
if (($target->assigned_to!='') && (($target->assigned_to!=$assigned_to)) && ($target!='')) {
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.owner_doesnt_match_asset'));
|
||||
}
|
||||
}
|
||||
@@ -332,7 +332,7 @@ class LicensesController extends Controller
|
||||
|
||||
// Was the asset updated?
|
||||
if ($licenseSeat->save()) {
|
||||
$licenseSeat->logCheckout($request->input('note'));
|
||||
$licenseSeat->logCheckout($request->input('note'), $target);
|
||||
|
||||
$data['license_id'] =$licenseSeat->license_id;
|
||||
$data['note'] = $request->input('note');
|
||||
|
||||
@@ -186,7 +186,7 @@ class ReportsController extends Controller
|
||||
{
|
||||
|
||||
// Grab all the assets
|
||||
$assets = Asset::with('model', 'assignedTo', 'assetstatus', 'defaultLoc', 'assetlog', 'company')
|
||||
$assets = Asset::with( 'assignedTo', 'assetstatus', 'defaultLoc', 'assetloc', 'assetlog', 'company', 'model.category', 'model.depreciation')
|
||||
->orderBy('created_at', 'DESC')->get();
|
||||
|
||||
return view('reports/depreciation', compact('assets'));
|
||||
@@ -390,7 +390,7 @@ class ReportsController extends Controller
|
||||
*/
|
||||
public function postCustom()
|
||||
{
|
||||
$assets = Asset::orderBy('created_at', 'DESC')->with('company', 'assigneduser', 'assetloc', 'defaultLoc', 'assigneduser.userloc', 'model', 'supplier', 'assetstatus', 'model.manufacturer')->get();
|
||||
$assets = Asset::orderBy('created_at', 'DESC')->with('company', 'assignedTo', 'assetloc', 'defaultLoc', 'model', 'supplier', 'assetstatus', 'model.manufacturer')->get();
|
||||
$customfields = CustomField::get();
|
||||
|
||||
$rows = [ ];
|
||||
@@ -552,8 +552,8 @@ class ReportsController extends Controller
|
||||
|
||||
if (e(Input::get('username')) == '1') {
|
||||
// Only works if we're checked out to a user, not anything else.
|
||||
if ($asset->assigneduser) {
|
||||
$row[] = '"' .e($asset->assigneduser->username). '"';
|
||||
if ($asset->checkedOutToUser()) {
|
||||
$row[] = '"' .e($asset->assignedTo->username). '"';
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
@@ -561,8 +561,8 @@ class ReportsController extends Controller
|
||||
|
||||
if (e(Input::get('employee_num')) == '1') {
|
||||
// Only works if we're checked out to a user, not anything else.
|
||||
if ($asset->assigneduser) {
|
||||
$row[] = '"' .e($asset->assigneduser->employee_num). '"';
|
||||
if ($asset->checkedOutToUser()) {
|
||||
$row[] = '"' .e($asset->assignedTo->employee_num). '"';
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ use Auth;
|
||||
use App\Models\User;
|
||||
use App\Http\Requests\SetupUserRequest;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Requests\SettingsLdapRequest;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Settings for
|
||||
@@ -562,10 +563,12 @@ class SettingsController extends Controller
|
||||
$alert_email = rtrim($request->input('alert_email'), ',');
|
||||
$alert_email = trim($alert_email);
|
||||
|
||||
$setting->alert_email = e($alert_email);
|
||||
$setting->alert_email = $alert_email;
|
||||
$setting->alerts_enabled = $request->input('alerts_enabled', '0');
|
||||
$setting->alert_interval = $request->input('alert_interval');
|
||||
$setting->alert_threshold = $request->input('alert_threshold');
|
||||
$setting->audit_interval = $request->input('audit_interval');
|
||||
$setting->audit_warning_days = $request->input('audit_warning_days');
|
||||
|
||||
if ($setting->save()) {
|
||||
return redirect()->route('settings.index')
|
||||
|
||||
@@ -1151,21 +1151,7 @@ class UsersController extends Controller
|
||||
}
|
||||
return redirect()->route('ldap/user')->with('success', "LDAP Import successful.")->with('summary', $summary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON containing a list of assets assigned to a user.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @param $userId
|
||||
* @return string JSON
|
||||
*/
|
||||
public function getAssetList($userId)
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
$assets = Asset::where('assigned_to', '=', $userId)->with('model')->get();
|
||||
return response()->json($assets);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exports users to CSV
|
||||
|
||||
@@ -68,8 +68,8 @@ class ViewAssetsController extends Controller
|
||||
public function getRequestableIndex()
|
||||
{
|
||||
|
||||
$assets = Asset::with('model', 'defaultLoc', 'assetloc', 'assignedTo')->Hardware()->RequestableAssets()->get();
|
||||
$models = AssetModel::with('category')->RequestableModels()->get();
|
||||
$assets = Asset::with('model', 'defaultLoc', 'assetloc', 'assignedTo', 'requests')->Hardware()->RequestableAssets()->get();
|
||||
$models = AssetModel::with('category', 'requests', 'assets')->RequestableModels()->get();
|
||||
|
||||
return view('account/requestable-assets', compact('user', 'assets', 'models'));
|
||||
}
|
||||
|
||||
@@ -34,14 +34,14 @@ class SaveUserRequest extends Request
|
||||
case 'POST':
|
||||
{
|
||||
$rules['first_name'] = 'required|string|min:1';
|
||||
$rules['username'] = 'required|string|min:1';
|
||||
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
|
||||
$rules['password'] = Setting::passwordComplexityRulesSaving('store');
|
||||
}
|
||||
|
||||
// Save all fields
|
||||
case 'PUT':
|
||||
$rules['first_name'] = 'required|string|min:1';
|
||||
$rules['username'] = 'required|string|min:1';
|
||||
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
|
||||
$rules['password'] = Setting::passwordComplexityRulesSaving('update');
|
||||
|
||||
// Save only what's passed
|
||||
|
||||
50
app/Http/Requests/SettingsLdapRequest.php
Normal file
50
app/Http/Requests/SettingsLdapRequest.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Session;
|
||||
|
||||
class SettingsLdapRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
"ldap_server" => 'sometimes|required_if:ldap_enabled,1|url|nullable',
|
||||
"ldap_uname" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_basedn" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_filter" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_username_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_fname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_lname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_auth_filter_query" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_version" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
];
|
||||
|
||||
return $rules;
|
||||
|
||||
}
|
||||
|
||||
public function response(array $errors)
|
||||
{
|
||||
$this->session()->flash('errors', Session::get('errors', new \Illuminate\Support\ViewErrorBag)
|
||||
->put('default', new \Illuminate\Support\MessageBag($errors)));
|
||||
\Input::flash();
|
||||
return parent::response($errors);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Setting;
|
||||
use Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use App\Helpers\Helper;
|
||||
@@ -12,24 +13,32 @@ class ActionlogsTransformer
|
||||
public function transformActionlogs (Collection $actionlogs, $total)
|
||||
{
|
||||
$array = array();
|
||||
$settings = Setting::getSettings();
|
||||
foreach ($actionlogs as $actionlog) {
|
||||
$array[] = self::transformActionlog($actionlog);
|
||||
$array[] = self::transformActionlog($actionlog, $settings);
|
||||
}
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
public function transformActionlog (Actionlog $actionlog)
|
||||
public function transformActionlog (Actionlog $actionlog, $settings = null)
|
||||
{
|
||||
$array = [
|
||||
'id' => (int) $actionlog->id,
|
||||
'icon' => $actionlog->present()->icon(),
|
||||
'image' => (method_exists($actionlog->item, 'getImageUrl')) ? $actionlog->item->getImageUrl() : null,
|
||||
'item' => ($actionlog->item) ? [
|
||||
'id' => (int) $actionlog->item->id,
|
||||
'name' => e($actionlog->item->getDisplayNameAttribute()),
|
||||
'type' => e($actionlog->itemType()),
|
||||
] : null,
|
||||
'location' => ($actionlog->location) ? [
|
||||
'id' => (int) $actionlog->location->id,
|
||||
'name' => e($actionlog->location->name)
|
||||
] : null,
|
||||
'created_at' => Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($actionlog->updated_at, 'datetime'),
|
||||
'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->item->next_audit_date, 'datetime'): null,
|
||||
'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(), 'date'): null,
|
||||
'days_to_next_audit' => $actionlog->daysUntilNextAudit($settings->audit_interval, $actionlog->item),
|
||||
'action_type' => $actionlog->present()->actionType(),
|
||||
'admin' => ($actionlog->user) ? [
|
||||
'id' => (int) $actionlog->user->id,
|
||||
|
||||
@@ -38,6 +38,7 @@ class AssetMaintenancesTransformer
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'update' => (bool) Gate::allows('update', Asset::class),
|
||||
'delete' => (bool) Gate::allows('delete', Asset::class),
|
||||
];
|
||||
|
||||
|
||||
@@ -62,14 +62,7 @@ class AssetsTransformer
|
||||
'name'=> e($asset->defaultLoc->name)
|
||||
] : null,
|
||||
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
|
||||
'assigned_to' => ($asset->assigneduser) ? [
|
||||
'id' => (int) $asset->assigneduser->id,
|
||||
'username' => e($asset->assigneduser->username),
|
||||
'name' => e($asset->assigneduser->getFullNameAttribute()),
|
||||
'first_name'=> e($asset->assigneduser->first_name),
|
||||
'last_name'=> e($asset->assigneduser->last_name),
|
||||
'employee_number' => e($asset->assigneduser->employee_num),
|
||||
] : null,
|
||||
'assigned_to' => $this->transformAssignedTo($asset),
|
||||
'warranty' => ($asset->warranty_months > 0) ? e($asset->warranty_months . ' ' . trans('admin/hardware/form.months')) : null,
|
||||
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
|
||||
'created_at' => Helper::getFormattedDateObject($asset->created_at, 'datetime'),
|
||||
@@ -130,4 +123,24 @@ class AssetsTransformer
|
||||
{
|
||||
return (new DatatablesTransformer)->transformDatatables($assets);
|
||||
}
|
||||
|
||||
public function transformAssignedTo($asset)
|
||||
{
|
||||
if ($asset->checkedOutToUser()) {
|
||||
return $asset->assignedTo ? [
|
||||
'id' => (int) $asset->assignedTo->id,
|
||||
'username' => e($asset->assignedTo->username),
|
||||
'name' => e($asset->assignedTo->getFullNameAttribute()),
|
||||
'first_name'=> e($asset->assignedTo->first_name),
|
||||
'last_name'=> e($asset->assignedTo->last_name),
|
||||
'employee_number' => e($asset->assignedTo->employee_num),
|
||||
'type' => 'user'
|
||||
] : null;
|
||||
}
|
||||
return $asset->assignedTo ? [
|
||||
'id' => $asset->assignedTo->id,
|
||||
'name' => $asset->assignedTo->display_name,
|
||||
'type' => $asset->assignedType()
|
||||
] : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,14 +136,12 @@ abstract class Importer
|
||||
* @param $default string
|
||||
* @return string
|
||||
*/
|
||||
public function findCsvMatch(array $array, $key, $default = '')
|
||||
public function findCsvMatch(array $array, $key, $default = null)
|
||||
{
|
||||
|
||||
$val = $default;
|
||||
|
||||
if ($customKey = $this->lookupCustomKey($key)) {
|
||||
$key = $customKey;
|
||||
}
|
||||
$key = $this->lookupCustomKey($key);
|
||||
|
||||
$this->log("Custom Key: ${key}");
|
||||
if (array_key_exists($key, $array)) {
|
||||
@@ -169,7 +167,8 @@ abstract class Importer
|
||||
$this->log("Found a match in our custom map: {$key} is " . $this->fieldMap[$key]);
|
||||
return $this->fieldMap[$key];
|
||||
}
|
||||
return null;
|
||||
// Otherwise no custom key, return original.
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -90,7 +90,6 @@ class ItemImporter extends Importer
|
||||
$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) {
|
||||
|
||||
@@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Response;
|
||||
use Carbon;
|
||||
|
||||
/**
|
||||
* Model for the Actionlog (the table that keeps a historical log of
|
||||
@@ -123,6 +124,10 @@ class Actionlog extends SnipeModel
|
||||
return $this->belongsTo('\App\Models\ActionLog', 'thread_id');
|
||||
}
|
||||
|
||||
public function location() {
|
||||
return $this->belongsTo('\App\Models\Location', 'location_id' )->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file exists, and if it does, force a download
|
||||
**/
|
||||
@@ -149,6 +154,33 @@ class Actionlog extends SnipeModel
|
||||
}
|
||||
}
|
||||
|
||||
public function daysUntilNextAudit($monthInterval = 12, $asset = null) {
|
||||
|
||||
$now = Carbon::now();
|
||||
$last_audit_date = $this->created_at;
|
||||
$next_audit = $last_audit_date->addMonth($monthInterval);
|
||||
$next_audit_days = $now->diffInDays($next_audit);
|
||||
|
||||
// Override the default setting for interval if the asset has its own next audit date
|
||||
if (($asset) && ($asset->next_audit_date)) {
|
||||
$override_default_next = \Carbon::parse($asset->next_audit_date);
|
||||
$next_audit_days = $override_default_next->diffInDays($now);
|
||||
}
|
||||
|
||||
return $next_audit_days;
|
||||
}
|
||||
|
||||
public function calcNextAuditDate($monthInterval = 12, $asset = null) {
|
||||
|
||||
$last_audit_date = Carbon::parse($this->created_at);
|
||||
// If there is an asset-specific next date already given,
|
||||
if (($asset) && ($asset->next_audit_date)) {
|
||||
return \Carbon::parse($asset->next_audit_date);
|
||||
}
|
||||
|
||||
return \Carbon::parse($last_audit_date)->addMonths($monthInterval)->toDateString();
|
||||
}
|
||||
|
||||
/**
|
||||
* getListingOfActionLogsChronologicalOrder
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\CheckoutNotAllowed;
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Presenters\Presentable;
|
||||
use AssetPresenter;
|
||||
@@ -10,6 +11,7 @@ use Config;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Log;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
/**
|
||||
* Model for Assets.
|
||||
@@ -19,7 +21,7 @@ use Watson\Validating\ValidatingTrait;
|
||||
class Asset extends Depreciable
|
||||
{
|
||||
protected $presenter = 'App\Presenters\AssetPresenter';
|
||||
use Loggable, Requestable, Presentable;
|
||||
use Loggable, Requestable, Presentable, Notifiable;
|
||||
use SoftDeletes;
|
||||
|
||||
const LOCATION = 'location';
|
||||
@@ -66,6 +68,7 @@ class Asset extends Depreciable
|
||||
'asset_tag' => 'required|min:1|max:255|unique_undeleted',
|
||||
'status' => 'integer',
|
||||
'purchase_cost' => 'numeric|nullable',
|
||||
'next_audit_date' => 'date|nullable',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -140,7 +143,7 @@ class Asset extends Depreciable
|
||||
* @return bool
|
||||
*/
|
||||
//FIXME: The admin parameter is never used. Can probably be removed.
|
||||
public function checkOut($target, $admin, $checkout_at = null, $expected_checkin = null, $note = null, $name = null)
|
||||
public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null)
|
||||
{
|
||||
if (!$target) {
|
||||
return false;
|
||||
@@ -160,41 +163,19 @@ class Asset extends Depreciable
|
||||
}
|
||||
|
||||
if ($this->requireAcceptance()) {
|
||||
if(get_class($target) != User::class) {
|
||||
throw new CheckoutNotAllowed;
|
||||
}
|
||||
$this->accepted="pending";
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
$this->logCheckout($note, $target);
|
||||
// if ((($this->requireAcceptance()=='1') || ($this->getEula())) && ($user->email!='')) {
|
||||
// $this->checkOutNotifyMail($log->id, $user, $checkout_at, $expected_checkin, $note);
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkOutNotifyMail($log_id, $user, $checkout_at, $expected_checkin, $note)
|
||||
{
|
||||
$data['log_id'] = $log_id;
|
||||
$data['eula'] = $this->getEula();
|
||||
$data['first_name'] = $user->first_name;
|
||||
$data['item_name'] = $this->present()->name();
|
||||
$data['checkout_date'] = $checkout_at;
|
||||
$data['expected_checkin'] = $expected_checkin;
|
||||
$data['item_tag'] = $this->asset_tag;
|
||||
$data['note'] = $note;
|
||||
$data['item_serial'] = $this->serial;
|
||||
$data['require_acceptance'] = $this->requireAcceptance();
|
||||
|
||||
if ((($this->requireAcceptance()=='1') || ($this->getEula())) && (!config('app.lock_passwords'))) {
|
||||
\Mail::send('emails.accept-asset', $data, function ($m) use ($user) {
|
||||
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
|
||||
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
|
||||
$m->subject(trans('mail.Confirm_asset_delivery'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function getDetailedNameAttribute()
|
||||
{
|
||||
if ($this->assignedTo) {
|
||||
@@ -246,16 +227,14 @@ class Asset extends Depreciable
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Even though we allow allow for checkout to things beyond users
|
||||
* this method is an easy way of seeing if we are checked out to a user.
|
||||
* @return mixed
|
||||
*/
|
||||
public function assigneduser()
|
||||
public function checkedOutToUser()
|
||||
{
|
||||
return $this->belongsTo('\App\Models\User', 'assigned_to')
|
||||
->withTrashed();
|
||||
return $this->assignedType() === self::USER;
|
||||
}
|
||||
|
||||
public function assignedTo()
|
||||
@@ -279,14 +258,13 @@ class Asset extends Depreciable
|
||||
}
|
||||
if ($this->assignedType() == self::LOCATION) {
|
||||
return $this->assignedTo();
|
||||
} elseif (!$this->assignedTo) {
|
||||
return $this->defaultLoc();
|
||||
} elseif ($this->assignedType() == self::USER) {
|
||||
return $this->assignedTo->userLoc();
|
||||
}
|
||||
if ($this->assignedType() == self::USER) {
|
||||
return $this->assignedTo->userLoc();
|
||||
}
|
||||
if (!$this->assignedTo) {
|
||||
return $this->defaultLoc();
|
||||
}
|
||||
}
|
||||
return $this->defaultLoc();
|
||||
}
|
||||
@@ -548,7 +526,7 @@ class Asset extends Depreciable
|
||||
|
||||
|
||||
/**
|
||||
* Query builder scope for pending assets
|
||||
* Query builder scope for searching location
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
*
|
||||
@@ -558,8 +536,17 @@ class Asset extends Depreciable
|
||||
public function scopeAssetsByLocation($query, $location)
|
||||
{
|
||||
return $query->where(function ($query) use ($location) {
|
||||
$query->whereHas('assigneduser', function ($query) use ($location) {
|
||||
$query->where('users.location_id', '=', $location->id);
|
||||
$query->whereHas('assignedTo', function ($query) use ($location) {
|
||||
$query->where([
|
||||
['users.location_id', '=', $location->id],
|
||||
['assets.assigned_type', '=', User::class]
|
||||
])->orWhere([
|
||||
['locations.id', '=', $location->id],
|
||||
['assets.assigned_type', '=', Location::class]
|
||||
])->orWhere([
|
||||
['assets.rtd_location_id', '=', $location->id],
|
||||
['assets.assigned_type', '=', Asset::class]
|
||||
]);
|
||||
})->orWhere(function ($query) use ($location) {
|
||||
$query->where('assets.rtd_location_id', '=', $location->id);
|
||||
$query->whereNull('assets.assigned_to');
|
||||
@@ -779,18 +766,26 @@ class Asset extends Depreciable
|
||||
$query->whereHas('defaultLoc', function ($query) use ($search) {
|
||||
$query->where('locations.name', 'LIKE', '%'.$search.'%');
|
||||
});
|
||||
})->orWhere(function ($query) use ($search) {
|
||||
$query->whereHas('assigneduser', function ($query) use ($search) {
|
||||
$query->where(function ($query) use ($search) {
|
||||
$query->where('users.first_name', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('users.last_name', 'LIKE', '%'.$search.'%')
|
||||
->orWhere(function ($query) use ($search) {
|
||||
$query->whereHas('userloc', function ($query) use ($search) {
|
||||
$query->where('locations.name', 'LIKE', '%'.$search.'%');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
//FIXME: This needs attention to work with checkout to not-users.
|
||||
// })->orWhere(function ($query) use ($search) {
|
||||
// $query->whereHas('assignedTo', function ($query) use ($search) {
|
||||
// $query->where(function ($query) use ($search) {
|
||||
// $query->where('assets.assigned_type', '=', User::class)
|
||||
// ->join('users', 'users.id', '=', 'assets.assigned_to')
|
||||
// ->where(function($query) use ($search) {
|
||||
// $query->where('users.first_name', 'LIKE', '%'.$search.'%')
|
||||
// ->orWhere('users.last_name', 'LIKE', '%'.$search.'%');
|
||||
// });
|
||||
// })->orWhere(function ($query) use ($search) {
|
||||
// $query->where('assets.assigned_type', '=', Location::class)
|
||||
// ->join('locations', 'locations.id', '=', 'assets.assigned_to')
|
||||
// ->where('locations.name', 'LIKE', '%'.$search.'%');
|
||||
// })->orWhere(function ($query) use ($search) {
|
||||
// $query->where('assets.assigned_type', '=', Asset::class)
|
||||
// ->join('assets as assigned_asset', 'assigned_assets.id', '=', 'assets.assigned_to')
|
||||
// ->where('assigned_assets.name', 'LIKE', '%'.$search.'%');
|
||||
// });
|
||||
// });
|
||||
})->orWhere('assets.name', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('assets.asset_tag', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('assets.serial', 'LIKE', '%'.$search.'%')
|
||||
@@ -1093,13 +1088,15 @@ class Asset extends Depreciable
|
||||
$query->whereHas('defaultLoc', function ($query) use ($search) {
|
||||
$query->where('locations.id', '=', $search);
|
||||
});
|
||||
})->orWhere(function ($query) use ($search) {
|
||||
$query->whereHas('assigneduser', function ($query) use ($search) {
|
||||
$query->whereHas('userloc', function ($query) use ($search) {
|
||||
$query->where('locations.id', '=', $search);
|
||||
});
|
||||
});
|
||||
});
|
||||
// FIXME: This needs porting to checkout to non-user.
|
||||
// ->orWhere(function ($query) use ($search) {
|
||||
// $query->whereHas('assigneduser', function ($query) use ($search) {
|
||||
// $query->whereHas('userloc', function ($query) use ($search) {
|
||||
// $query->where('locations.id', '=', $search);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ class Consumable extends SnipeModel
|
||||
return $this->belongsTo('\App\Models\User', 'user_id');
|
||||
}
|
||||
|
||||
public function consumableAssigments()
|
||||
public function consumableAssignments()
|
||||
{
|
||||
return $this->hasMany('\App\Models\ConsumableAssignment');
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ class Ldap extends Model
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$user = array_change_key_case(ldap_get_attributes($connection, $entry), CASE_LOWER)) {
|
||||
if (!$user = ldap_get_attributes($connection, $entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,56 @@ trait Loggable
|
||||
* @since [v3.4]
|
||||
* @return \App\Models\Actionlog
|
||||
*/
|
||||
public function logCheckout($note, $target = null /*target is overridable for components*/)
|
||||
public function logCheckout($note, $target /* What are we checking out to? */)
|
||||
{
|
||||
$log = new Actionlog;
|
||||
$log = $this->determineLogItemType($log);
|
||||
$log->user_id = Auth::user()->id;
|
||||
|
||||
// We need to special case licenses because of license_seat vs license. So much for clean polymorphism :)
|
||||
if (!isset($target)) {
|
||||
throw new Exception('All checkout logs require a target');
|
||||
return;
|
||||
}
|
||||
$log->target_type = get_class($target);
|
||||
$log->target_id = $target->id;
|
||||
|
||||
$class = get_class($target);
|
||||
if ($class == Location::class) {
|
||||
// We can checkout to a location
|
||||
$log->location_id = $target->id;
|
||||
} else if ($class== Asset::class) {
|
||||
$log->location_id = $target->rtd_location_id;
|
||||
} else {
|
||||
$log->location_id = $target->location_id;
|
||||
}
|
||||
$log->note = $note;
|
||||
$log->logaction('checkout');
|
||||
|
||||
$params = [
|
||||
'item' => $this,
|
||||
'target' => $target,
|
||||
'admin' => $log->user,
|
||||
'note' => $note,
|
||||
'log_id' => $log->id
|
||||
];
|
||||
|
||||
if ($settings = Setting::getSettings()) {
|
||||
$settings->notify(new CheckoutNotification($params));
|
||||
}
|
||||
|
||||
if (method_exists($target, 'notify')) {
|
||||
$target->notify(new CheckoutNotification($params));
|
||||
}
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine the log item type
|
||||
*/
|
||||
private function determineLogItemType($log)
|
||||
{
|
||||
// We need to special case licenses because of license_seat vs license. So much for clean polymorphism :
|
||||
if (static::class == LicenseSeat::class) {
|
||||
$log->item_type = License::class;
|
||||
$log->item_id = $this->license_id;
|
||||
@@ -43,52 +88,8 @@ trait Loggable
|
||||
$log->item_id = $this->id;
|
||||
}
|
||||
|
||||
$log->user_id = Auth::user()->id;
|
||||
|
||||
// @FIXME This needs to be generalized with new asset checkout.
|
||||
if(isset($target)) {
|
||||
$log->target_type = get_class($target);
|
||||
$log->target_id = $target->id;
|
||||
} else {
|
||||
if (!is_null($this->asset_id)) {
|
||||
$log->target_type = Asset::class;
|
||||
$log->target_id = $this->asset_id;
|
||||
} elseif (!is_null($this->assigned_to)) {
|
||||
$log->target_type = User::class;
|
||||
$log->target_id = $this->assigned_to;
|
||||
}
|
||||
}
|
||||
|
||||
$item = call_user_func(array($log->target_type, 'find'), $log->target_id);
|
||||
if($this->assignedTo) {
|
||||
$item = $this->assignedTo;
|
||||
}
|
||||
$class = get_class($item);
|
||||
if($class == Location::class) {
|
||||
// We can checkout to a location
|
||||
$log->location_id = $item->id;
|
||||
} else if ($class== Asset::class) {
|
||||
$log->location_id = $item->rtd_location_id;
|
||||
} else {
|
||||
$log->location_id = $item->location_id;
|
||||
}
|
||||
$log->note = $note;
|
||||
$log->logaction('checkout');
|
||||
|
||||
$params = [
|
||||
'item' => $log->item,
|
||||
'target' => $log->target,
|
||||
'admin' => $log->user,
|
||||
'note' => $note
|
||||
];
|
||||
|
||||
if ($settings = Setting::getSettings()) {
|
||||
$settings->notify(new CheckoutNotification($params));
|
||||
}
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Daniel Meltzer <parallelgrapefruit@gmail.com
|
||||
* @since [v3.4]
|
||||
@@ -127,9 +128,10 @@ trait Loggable
|
||||
* @since [v4.0]
|
||||
* @return \App\Models\Actionlog
|
||||
*/
|
||||
public function logAudit($note)
|
||||
public function logAudit($note, $location_id)
|
||||
{
|
||||
$log = new Actionlog;
|
||||
$location = Location::find($location_id);
|
||||
if (static::class == LicenseSeat::class) {
|
||||
$log->item_type = License::class;
|
||||
$log->item_id = $this->license_id;
|
||||
@@ -137,7 +139,7 @@ trait Loggable
|
||||
$log->item_type = static::class;
|
||||
$log->item_id = $this->id;
|
||||
}
|
||||
$log->location_id = null;
|
||||
$log->location_id = ($location_id) ? $location_id : null;
|
||||
$log->note = $note;
|
||||
$log->user_id = Auth::user()->id;
|
||||
$log->logaction('audit');
|
||||
@@ -145,6 +147,7 @@ trait Loggable
|
||||
$params = [
|
||||
'item' => $log->item,
|
||||
'admin' => $log->user,
|
||||
'location' => ($location) ? $location->name : '',
|
||||
'note' => $note
|
||||
];
|
||||
Setting::getSettings()->notify(new AuditNotification($params));
|
||||
@@ -153,6 +156,7 @@ trait Loggable
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Daniel Meltzer <parallelgrapefruit@gmail.com
|
||||
* @since [v3.5]
|
||||
|
||||
@@ -19,9 +19,9 @@ trait Requestable
|
||||
|
||||
public function isRequestedBy(User $user)
|
||||
{
|
||||
return $this->requests()
|
||||
->where('user_id', $user->id)
|
||||
->exists();
|
||||
$requests = $this->requests->where('user_id', $user->id);
|
||||
|
||||
return $requests->count() > 0;
|
||||
}
|
||||
|
||||
public function scopeRequestedBy($query, User $user)
|
||||
|
||||
@@ -34,17 +34,10 @@ class Setting extends Model
|
||||
'labels_fontsize' => 'numeric|min:5',
|
||||
'labels_pagewidth' => 'numeric|nullable',
|
||||
'labels_pageheight' => 'numeric|nullable',
|
||||
"ldap_server" => 'sometimes|required_if:ldap_enabled,1|url|nullable',
|
||||
"ldap_uname" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_basedn" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_filter" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_username_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_fname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_lname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_auth_filter_query" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_version" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"thumbnail_max_h" => 'numeric|max:500|min:25',
|
||||
"pwd_secure_min" => "numeric|required|min:5",
|
||||
"audit_warning_days" => "numeric|nullable",
|
||||
"audit_interval" => "numeric|nullable",
|
||||
];
|
||||
|
||||
protected $fillable = ['site_name','email_domain','email_format','username_format'];
|
||||
|
||||
@@ -82,4 +82,8 @@ class SnipeModel extends Model
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function name() {
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +56,9 @@ class AuditNotification extends Notification
|
||||
'By' => '<'.$admin_user->present()->viewUrl().'|'.$admin_user->present()->fullName().'>'
|
||||
];
|
||||
array_key_exists('note', $this->params) && $fields['Notes'] = $this->params['note'];
|
||||
array_key_exists('location', $this->params) && $fields['Location'] = $this->params['location'];
|
||||
|
||||
$attachment->title($item->name, $item->present()->viewUrl())
|
||||
$attachment->title($item->present()->name, $item->present()->viewUrl())
|
||||
->fields($fields);
|
||||
});
|
||||
}
|
||||
@@ -69,10 +70,7 @@ class AuditNotification extends Notification
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->line('The introduction to the notification.')
|
||||
->action('Notification Action', 'https://laravel.com')
|
||||
->line('Thank you for using our application!');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,10 +5,11 @@ namespace App\Notifications;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class CheckoutNotification extends Notification
|
||||
{
|
||||
@@ -43,11 +44,12 @@ class CheckoutNotification extends Notification
|
||||
}
|
||||
$item = $this->params['item'];
|
||||
|
||||
if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance()=='1'))
|
||||
|| (method_exists($item, 'getEula') && ($item->getEula()))
|
||||
) {
|
||||
$notifyBy[] = 'mail';
|
||||
}
|
||||
$notifyBy[]='mail';
|
||||
// if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance()=='1'))
|
||||
// || (method_exists($item, 'getEula') && ($item->getEula()))
|
||||
// ) {
|
||||
// $notifyBy[] = 'mail';
|
||||
// }
|
||||
return $notifyBy;
|
||||
}
|
||||
|
||||
@@ -79,10 +81,30 @@ class CheckoutNotification extends Notification
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
//TODO: Expand for non assets.
|
||||
$item = $this->params['item'];
|
||||
$admin_user = $this->params['admin'];
|
||||
$target = $this->params['target'];
|
||||
$data = [
|
||||
'eula' => method_exists($item, 'getEula') ? $item->getEula() : '',
|
||||
'first_name' => $target->present()->fullName(),
|
||||
'item_name' => $item->present()->name(),
|
||||
'checkout_date' => $item->last_checkout,
|
||||
'expected_checkin' => $item->expected_checkin,
|
||||
'item_tag' => $item->asset_tag,
|
||||
'note' => $this->params['note'],
|
||||
'item_serial' => $item->serial,
|
||||
'require_acceptance' => $item->requireAcceptance(),
|
||||
'log_id' => $this->params['log_id'],
|
||||
];
|
||||
return (new MailMessage)
|
||||
->line('The introduction to the notification.')
|
||||
->action('Notification Action', 'https://laravel.com')
|
||||
->line('Thank you for using our application!');
|
||||
->view('emails.accept-asset', $data)
|
||||
->subject(trans('mail.Confirm_asset_delivery'));
|
||||
// \Mail::send('emails.accept-asset', $data, function ($m) use ($target) {
|
||||
// $m->to($target->email, $target->first_name . ' ' . $target->last_name);
|
||||
// $m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
|
||||
// $m->subject(trans('mail.Confirm_asset_delivery'));
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
86
app/Notifications/ExpectedCheckinNotification.php
Normal file
86
app/Notifications/ExpectedCheckinNotification.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class ExpectedCheckinNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $params;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
{
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
$notifyBy = [];
|
||||
$item = $this->params['item'];
|
||||
|
||||
$notifyBy[]='mail';
|
||||
return $notifyBy;
|
||||
}
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $asset
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($params)
|
||||
{
|
||||
$formatted_due = Carbon::parse($this->params->expected_checkin)->format('D, M j, Y');
|
||||
return (new MailMessage)
|
||||
->error()
|
||||
->subject('Reminder: '.$this->params->present()->name().' checkin deadline approaching')
|
||||
->line('Hi, '.$this->params->assignedto->first_name)
|
||||
->greeting('An asset checked out to you is due to be checked back in on '.$formatted_due.'.')
|
||||
->line('Asset: '.$this->params->present()->name())
|
||||
->line('Serial: '.$this->params->serial)
|
||||
->line('Asset Tag: '.$this->params->asset_tag)
|
||||
->action('View Your Assets', route('view-assets'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ class AssetPresenter extends Presenter
|
||||
"sortable" => true,
|
||||
"title" => trans('admin/hardware/form.checkedout_to'),
|
||||
"visible" => true,
|
||||
"formatter" => "usersLinkObjFormatter"
|
||||
"formatter" => "polymorphicItemFormatter"
|
||||
], [
|
||||
"field" => "employee_number",
|
||||
"searchable" => false,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
return array (
|
||||
'app_version' => 'v4.0',
|
||||
'build_version' => 'beta3',
|
||||
'hash_version' => '22',
|
||||
'full_hash' => 'v4.0-beta3-22-gbd02b9e',
|
||||
'app_version' => 'v4',
|
||||
'build_version' => 'beta4',
|
||||
'hash_version' => '24',
|
||||
'full_hash' => 'v4-beta4-24-g10f3221',
|
||||
);
|
||||
|
||||
@@ -20,7 +20,7 @@ $factory->defineAs(Actionlog::class, 'asset-checkout', function (Faker\Generator
|
||||
$user = factory(App\Models\User::class)->create(['company_id' => $company->id]);
|
||||
$target = factory(App\Models\User::class)->create(['company_id' => $company->id]);
|
||||
// $item = factory(App\Models\Asset::class)->create(['company_id' => $company->id]);
|
||||
|
||||
// dd($item);
|
||||
return [
|
||||
'user_id' => $user->id,
|
||||
'action_type' => 'checkout',
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -69,6 +71,13 @@ $factory->state(Asset::class, 'assigned-to-asset', function ($faker) {
|
||||
];
|
||||
});
|
||||
|
||||
$factory->state(Asset::class, 'requires-acceptance', function ($faker) {
|
||||
$cat = factory(Category::class)->states('asset-category', 'requires-acceptance')->create();
|
||||
$model = factory(AssetModel::class)->create(['category_id' => $cat->id]);
|
||||
return [
|
||||
'model_id' => $model->id
|
||||
];
|
||||
});
|
||||
|
||||
$factory->define(App\Models\AssetModel::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
|
||||
@@ -15,7 +15,7 @@ $factory->define(App\Models\Category::class, function (Faker\Generator $faker) {
|
||||
'name' => $faker->text(20),
|
||||
'category_type' => $faker->randomElement(['asset', 'accessory', 'component', 'consumable']),
|
||||
'eula_text' => $faker->paragraph(),
|
||||
'require_acceptance' => $faker->boolean(),
|
||||
'require_acceptance' => false,
|
||||
'use_default_eula' => $faker->boolean(),
|
||||
'checkin_email' => $faker->boolean()
|
||||
];
|
||||
@@ -44,3 +44,9 @@ $factory->state(App\Models\Category::class, 'consumable-category', function ($fa
|
||||
'category_type' => 'consumable',
|
||||
];
|
||||
});
|
||||
|
||||
$factory->state(App\Models\Category::class, 'requires-acceptance', function ($faker) {
|
||||
return [
|
||||
'require_acceptance' => true,
|
||||
];
|
||||
});
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddAuditingToSettings extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->integer('audit_interval')->nullable()->default(NULL);
|
||||
$table->integer('audit_warning_days')->nullable()->default(NULL);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->dropColumn('audit_interval');
|
||||
$table->dropColumn('audit_warning_days');
|
||||
});
|
||||
}
|
||||
}
|
||||
80
gulpfile.js
80
gulpfile.js
@@ -1,80 +0,0 @@
|
||||
var elixir = require('laravel-elixir');
|
||||
require('laravel-elixir-codeception-standalone');
|
||||
require('laravel-elixir-phpcs');
|
||||
require('laravel-elixir-vue-2');
|
||||
var bowerPath = './bower_components';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Elixir Asset Management
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Elixir provides a clean, fluent API for defining some basic Gulp tasks
|
||||
| for your Laravel application. By default, we are compiling the Sass
|
||||
| file for our application, as well as publishing vendor resources.
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
elixir(function(mix) {
|
||||
|
||||
mix.less(
|
||||
[
|
||||
'app.less',
|
||||
bowerPath + '/iCheck/skins/minimal/*',
|
||||
'AdminLTE.less',
|
||||
'skins/skin-blue.less',
|
||||
'overrides.less'
|
||||
], 'public/assets/css/')
|
||||
.copy(bowerPath + '/bootstrap-less/assets/fonts/bootstrap/**', 'public/assets/fonts')
|
||||
.copy(bowerPath + '/font-awesome/fonts/*', 'public/build/fonts');
|
||||
|
||||
|
||||
|
||||
mix.webpack(
|
||||
// jQuery is loaded from vue.js webpack process
|
||||
'./resources/assets/js/vue.js',
|
||||
'./resources/assets/js/vue-dist.js'
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
mix.scripts([
|
||||
bowerPath + '/tether/dist/js/tether.js',
|
||||
'vue-dist.js',
|
||||
bowerPath + '/jquery-ui/jquery-ui.js',
|
||||
bowerPath + '/jquery-slimscroll/jquery.slimscroll.js',
|
||||
bowerPath + '/jquery.iframe-transport/jquery.iframe-transport.js',
|
||||
bowerPath + '/blueimp-file-upload/js/jquery.fileupload.js',
|
||||
bowerPath + '/fastclick/lib/fastclick.js',
|
||||
bowerPath + '/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js',
|
||||
bowerPath + '/bootstrap-datepicker/dist/js/bootstrap-datepicker.js',
|
||||
bowerPath + '/iCheck/icheck.js',
|
||||
bowerPath + '/select2/dist/js/select2.full.js',
|
||||
bowerPath + '/ekko-lightbox/dist/ekko-lightbox.js',
|
||||
'snipeit.js',
|
||||
'app.js'
|
||||
|
||||
],'public/assets/js');
|
||||
mix.version(['assets/css/app.css','assets/js/all.js']);
|
||||
|
||||
|
||||
// mix.codeception(null, { flags: '--report' });
|
||||
|
||||
|
||||
// mix.phpcs([
|
||||
// 'app/**/*.php',
|
||||
// 'tests/unit/*.php',
|
||||
// 'tests/functional/*.php',
|
||||
// 'tests/acceptance/*.php'
|
||||
// ], {
|
||||
// bin: 'vendor/bin/phpcs',
|
||||
// standard: 'PSR2'
|
||||
// });
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
28
public/js/dist/all.js
vendored
28
public/js/dist/all.js
vendored
File diff suppressed because one or more lines are too long
127
resources/assets/js/snipeit_modals.js
Normal file
127
resources/assets/js/snipeit_modals.js
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
*
|
||||
* Snipe-IT Universal Modal support
|
||||
*
|
||||
* Enables modal dialogs to create sub-resources throughout Snipe-IT
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
HOW TO USE
|
||||
|
||||
Create a Button looking like this:
|
||||
|
||||
<a href='{{ route('modal.user') }}' data-toggle="modal" data-target="#createModal" data-dependency="user" data-select='assigned_to' class="btn btn-sm btn-default">New</a>
|
||||
|
||||
If you don't have access to Blade commands (like {{ and }}, etc), you can hard-code a URL as the 'href'
|
||||
|
||||
data-toggle="modal" - required for Bootstrap Modals
|
||||
data-target="#createModal" - fixed ID for the modal, do not change
|
||||
data-dependency="user" - which Snipe-IT model you're going to be creating.
|
||||
data-select="assigned_to" - What is the *ID* of the select-dropdown that you're going to be adding to, if the modal-create was a
|
||||
success? Be on the lookout for duplicate ID's, it will confuse this library!
|
||||
class="btn btn-sm btn-default" - makes it look button-ey, feel free to change :)
|
||||
*/
|
||||
|
||||
$(function () {
|
||||
console.warn("Loading up Modal functionality.");
|
||||
|
||||
//handle modal-add-interstitial calls
|
||||
var model, select;
|
||||
|
||||
if($('#createModal').length == 0) {
|
||||
$('body').append('<div class="modal fade" id="createModal"></div><!-- /.modal -->');
|
||||
}
|
||||
|
||||
$('#createModal').on("show.bs.modal", function (event) {
|
||||
var link = $(event.relatedTarget);
|
||||
model = link.data("dependency");
|
||||
select = link.data("select");
|
||||
// console.warn("Uh, href is: "+link.attr('href'));
|
||||
// console.dir(link);
|
||||
$('#createModal').load(link.attr('href'),function () {
|
||||
//do we need to re-select2 this, after load? Probably.
|
||||
$('#createModal').find('select.select2').select2();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#createModal').on('click','#modal-save', function () {
|
||||
console.warn("MODAL SAVE CALLED FOR MODAL!");
|
||||
var data = {};
|
||||
console.warn("We are about to SAVE!!! for model: "+model+" and select ID: "+select);
|
||||
$('.modal-body input:visible').each(function (index, elem) {
|
||||
console.warn("["+index+"]: "+elem.id+" = "+$(elem).val());
|
||||
var bits = elem.id.split("-");
|
||||
if (bits[0] === "modal") {
|
||||
data[bits[1]] = $(elem).val();
|
||||
}
|
||||
});
|
||||
//this can probably get replaced with a normal 'serialize' instead
|
||||
$('.modal-body select:visible').each(function (index, elem) {
|
||||
var bits = elem.id.split("-");
|
||||
data[bits[1]] = $(elem).val();
|
||||
});
|
||||
|
||||
data._token = Laravel.csrfToken;
|
||||
console.log(data);
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: "/api/v1/" + model + "s",
|
||||
headers: {
|
||||
"X-Requested-With": 'XMLHttpRequest',
|
||||
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
|
||||
data: data,
|
||||
success: function (result) {
|
||||
// {"status":"error","messages":{"name":["The name field is required."]}}
|
||||
if(result.status == "error") {
|
||||
var error_message="";
|
||||
for(var field in result.messages) {
|
||||
error_message+="Problem(s) with field '"+field+"': "+result.messages[field].join(", ");
|
||||
}
|
||||
//window.alert("Error adding "+model+": "+error_message);
|
||||
$('#modal_error_msg').html(error_message).show();
|
||||
return false;
|
||||
}
|
||||
var id = result.payload.id;
|
||||
var name = result.payload.name || (result.payload.first_name + " " + result.payload.last_name);
|
||||
if(!id || !name) {
|
||||
console.error("Could not find resulting name or ID from modal-create. Name: "+name+", id: "+id);
|
||||
return false;
|
||||
}
|
||||
$('#createModal').modal('hide');
|
||||
$('#createModal').html("");
|
||||
|
||||
// "select" is the original drop-down menu that someone
|
||||
// clicked 'add' on to add a new 'thing'
|
||||
// this code adds the newly created object to that select
|
||||
var selector = document.getElementById(select);
|
||||
if(!selector) {
|
||||
console.error("Could not find original <select> element with an id of: "+select);
|
||||
return false;
|
||||
}
|
||||
//console.log(document.getElementById(select));
|
||||
console.dir(selector);
|
||||
selector.options[selector.length] = new Option(name, id);
|
||||
selector.selectedIndex = selector.length - 1;
|
||||
$(selector).trigger("change");
|
||||
if(fetchCustomFields) {
|
||||
fetchCustomFields();
|
||||
}
|
||||
|
||||
},
|
||||
error: function (result) {
|
||||
// console.log('Error: ' + result.responseJSON.error.message );
|
||||
msg = result.responseJSON.messages || result.responseJSON.error;
|
||||
$('#modal_error_msg').html("Server Error: "+msg).show();
|
||||
//window.alert("Unable to add new " + model + " - error: " + msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,7 @@ return array(
|
||||
'asset' => 'Asset',
|
||||
'bulk_checkout' => 'Checkout Assets to User',
|
||||
'checkin' => 'Checkin Asset',
|
||||
'checkout' => 'Checkout Asset to User',
|
||||
'checkout' => 'Checkout Asset',
|
||||
'clone' => 'Clone Asset',
|
||||
'deployable' => 'Deployable',
|
||||
'deleted' => 'This asset has been deleted. <a href="/hardware/:asset_id/restore">Click here to restore it</a>.',
|
||||
|
||||
@@ -10,6 +10,10 @@ return array(
|
||||
'alert_interval' => 'Expiring Alerts Threshold (in days)',
|
||||
'alert_inv_threshold' => 'Inventory Alert Threshold',
|
||||
'asset_ids' => 'Asset IDs',
|
||||
'audit_interval' => 'Audit Interval',
|
||||
'audit_interval_help' => 'If you are required to regularly physically audit your assets, enter the interval in months.',
|
||||
'audit_warning_days' => 'Audit Warning Threshold',
|
||||
'audit_warning_days_help' => 'How many days in advance should we warn you when assets are due for auditing?',
|
||||
'auto_increment_assets' => 'Generate auto-incrementing asset IDs',
|
||||
'auto_increment_prefix' => 'Prefix (optional)',
|
||||
'auto_incrementing_help' => 'Enable auto-incrementing asset IDs first to set this',
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
'avatar_upload' => 'Upload Avatar',
|
||||
'back' => 'Back',
|
||||
'bad_data' => 'Nothing found. Maybe bad data?',
|
||||
'bulkaudit' => 'Bulk Audit',
|
||||
'bulkaudit_status' => 'Audit Status',
|
||||
'bulk_checkout' => 'Bulk Checkout',
|
||||
'cancel' => 'Cancel',
|
||||
'categories' => 'Categories',
|
||||
@@ -54,6 +56,8 @@
|
||||
'current' => 'Current',
|
||||
'custom_report' => 'Custom Asset Report',
|
||||
'dashboard' => 'Dashboard',
|
||||
'days' => 'days',
|
||||
'days_to_next_audit' => 'Days to Next Audit',
|
||||
'date' => 'Date',
|
||||
'debug_warning' => 'Warning!',
|
||||
'debug_warning_text' => 'This application is running in production mode with debugging enabled. This can expose sensitive data if your application is accessible to the outside world. Disable debug mode by setting the <code>APP_DEBUG</code> value in your <code>.env</code> file to <code>false</code>.',
|
||||
|
||||
@@ -13,62 +13,91 @@ return array(
|
||||
|
|
||||
*/
|
||||
|
||||
"accepted" => "The :attribute must be accepted.",
|
||||
"active_url" => "The :attribute is not a valid URL.",
|
||||
"after" => "The :attribute must be a date after :date.",
|
||||
"alpha" => "The :attribute may only contain letters.",
|
||||
"alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.",
|
||||
"alpha_num" => "The :attribute may only contain letters and numbers.",
|
||||
"before" => "The :attribute must be a date before :date.",
|
||||
"between" => array(
|
||||
"numeric" => "The :attribute must be between :min - :max.",
|
||||
"file" => "The :attribute must be between :min - :max kilobytes.",
|
||||
"string" => "The :attribute must be between :min - :max characters.",
|
||||
),
|
||||
"boolean" => "The :attribute must be true or false.",
|
||||
"confirmed" => "The :attribute confirmation does not match.",
|
||||
"date" => "The :attribute is not a valid date.",
|
||||
"date_format" => "The :attribute does not match the format :format.",
|
||||
"different" => "The :attribute and :other must be different.",
|
||||
"digits" => "The :attribute must be :digits digits.",
|
||||
"digits_between" => "The :attribute must be between :min and :max digits.",
|
||||
"email" => "The :attribute format is invalid.",
|
||||
"exists" => "The selected :attribute is invalid.",
|
||||
"email_array" => "One or more email addresses is invalid.",
|
||||
"hashed_pass" => "Your current password is incorrect",
|
||||
'dumbpwd' => 'That password is too common.',
|
||||
"image" => "The :attribute must be an image.",
|
||||
"in" => "The selected :attribute is invalid.",
|
||||
"integer" => "The :attribute must be an integer.",
|
||||
"ip" => "The :attribute must be a valid IP address.",
|
||||
"max" => array(
|
||||
"numeric" => "The :attribute may not be greater than :max.",
|
||||
"file" => "The :attribute may not be greater than :max kilobytes.",
|
||||
"string" => "The :attribute may not be greater than :max characters.",
|
||||
),
|
||||
"mimes" => "The :attribute must be a file of type: :values.",
|
||||
"min" => array(
|
||||
"numeric" => "The :attribute must be at least :min.",
|
||||
"file" => "The :attribute must be at least :min kilobytes.",
|
||||
"string" => "The :attribute must be at least :min characters.",
|
||||
),
|
||||
"not_in" => "The selected :attribute is invalid.",
|
||||
"numeric" => "The :attribute must be a number.",
|
||||
"regex" => "The :attribute format is invalid.",
|
||||
"required" => "The :attribute field is required.",
|
||||
"required_if" => "The :attribute field is required when :other is :value.",
|
||||
"required_with" => "The :attribute field is required when :values is present.",
|
||||
"required_without" => "The :attribute field is required when :values is not present.",
|
||||
"same" => "The :attribute and :other must match.",
|
||||
"size" => array(
|
||||
"numeric" => "The :attribute must be :size.",
|
||||
"file" => "The :attribute must be :size kilobytes.",
|
||||
"string" => "The :attribute must be :size characters.",
|
||||
),
|
||||
"unique" => "The :attribute has already been taken.",
|
||||
"url" => "The :attribute format is invalid.",
|
||||
"statuslabel_type" => "You must select a valid status label type",
|
||||
"unique_undeleted" => "The :attribute must be unique.",
|
||||
'accepted' => 'The :attribute must be accepted.',
|
||||
'active_url' => 'The :attribute is not a valid URL.',
|
||||
'after' => 'The :attribute must be a date after :date.',
|
||||
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
|
||||
'alpha' => 'The :attribute may only contain letters.',
|
||||
'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
|
||||
'alpha_num' => 'The :attribute may only contain letters and numbers.',
|
||||
'array' => 'The :attribute must be an array.',
|
||||
'before' => 'The :attribute must be a date before :date.',
|
||||
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
|
||||
'between' => [
|
||||
'numeric' => 'The :attribute must be between :min and :max.',
|
||||
'file' => 'The :attribute must be between :min and :max kilobytes.',
|
||||
'string' => 'The :attribute must be between :min and :max characters.',
|
||||
'array' => 'The :attribute must have between :min and :max items.',
|
||||
],
|
||||
'boolean' => 'The :attribute field must be true or false.',
|
||||
'confirmed' => 'The :attribute confirmation does not match.',
|
||||
'date' => 'The :attribute is not a valid date.',
|
||||
'date_format' => 'The :attribute does not match the format :format.',
|
||||
'different' => 'The :attribute and :other must be different.',
|
||||
'digits' => 'The :attribute must be :digits digits.',
|
||||
'digits_between' => 'The :attribute must be between :min and :max digits.',
|
||||
'dimensions' => 'The :attribute has invalid image dimensions.',
|
||||
'distinct' => 'The :attribute field has a duplicate value.',
|
||||
'email' => 'The :attribute must be a valid email address.',
|
||||
'exists' => 'The selected :attribute is invalid.',
|
||||
'file' => 'The :attribute must be a file.',
|
||||
'filled' => 'The :attribute field must have a value.',
|
||||
'image' => 'The :attribute must be an image.',
|
||||
'in' => 'The selected :attribute is invalid.',
|
||||
'in_array' => 'The :attribute field does not exist in :other.',
|
||||
'integer' => 'The :attribute must be an integer.',
|
||||
'ip' => 'The :attribute must be a valid IP address.',
|
||||
'ipv4' => 'The :attribute must be a valid IPv4 address.',
|
||||
'ipv6' => 'The :attribute must be a valid IPv6 address.',
|
||||
'json' => 'The :attribute must be a valid JSON string.',
|
||||
'max' => [
|
||||
'numeric' => 'The :attribute may not be greater than :max.',
|
||||
'file' => 'The :attribute may not be greater than :max kilobytes.',
|
||||
'string' => 'The :attribute may not be greater than :max characters.',
|
||||
'array' => 'The :attribute may not have more than :max items.',
|
||||
],
|
||||
'mimes' => 'The :attribute must be a file of type: :values.',
|
||||
'mimetypes' => 'The :attribute must be a file of type: :values.',
|
||||
'min' => [
|
||||
'numeric' => 'The :attribute must be at least :min.',
|
||||
'file' => 'The :attribute must be at least :min kilobytes.',
|
||||
'string' => 'The :attribute must be at least :min characters.',
|
||||
'array' => 'The :attribute must have at least :min items.',
|
||||
],
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
'present' => 'The :attribute field must be present.',
|
||||
'regex' => 'The :attribute format is invalid.',
|
||||
'required' => 'The :attribute field is required.',
|
||||
'required_if' => 'The :attribute field is required when :other is :value.',
|
||||
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
||||
'required_with' => 'The :attribute field is required when :values is present.',
|
||||
'required_with_all' => 'The :attribute field is required when :values is present.',
|
||||
'required_without' => 'The :attribute field is required when :values is not present.',
|
||||
'required_without_all' => 'The :attribute field is required when none of :values are present.',
|
||||
'same' => 'The :attribute and :other must match.',
|
||||
'size' => [
|
||||
'numeric' => 'The :attribute must be :size.',
|
||||
'file' => 'The :attribute must be :size kilobytes.',
|
||||
'string' => 'The :attribute must be :size characters.',
|
||||
'array' => 'The :attribute must contain :size items.',
|
||||
],
|
||||
'string' => 'The :attribute must be a string.',
|
||||
'timezone' => 'The :attribute must be a valid zone.',
|
||||
'unique' => 'The :attribute has already been taken.',
|
||||
'uploaded' => 'The :attribute failed to upload.',
|
||||
'url' => 'The :attribute format is invalid.',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify custom validation messages for attributes using the
|
||||
| convention "attribute.rule" to name the lines. This makes it quick to
|
||||
| specify a specific custom language line for a given attribute rule.
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
@@ -82,8 +111,14 @@ return array(
|
||||
|
|
||||
*/
|
||||
|
||||
'custom' => array(),
|
||||
'alpha_space' => "The :attribute field contains a character that is not allowed.",
|
||||
'custom' => [
|
||||
'alpha_space' => "The :attribute field contains a character that is not allowed.",
|
||||
"email_array" => "One or more email addresses is invalid.",
|
||||
"hashed_pass" => "Your current password is incorrect",
|
||||
'dumbpwd' => 'That password is too common.',
|
||||
"statuslabel_type" => "You must select a valid status label type",
|
||||
"unique_undeleted" => "The :attribute must be unique.",
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -96,6 +131,6 @@ return array(
|
||||
|
|
||||
*/
|
||||
|
||||
'attributes' => array(),
|
||||
'attributes' => [],
|
||||
|
||||
);
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
>
|
||||
{{ csrf_field() }}
|
||||
<td>{{$requestableModel->name}}</td>
|
||||
<td>{{$requestableModel->assets()->where('requestable', '1')->count()}}</td>
|
||||
<td>{{$requestableModel->assets->where('requestable', '1')->count()}}</td>
|
||||
<td><input type="text" name="request-quantity" value=""></td>
|
||||
<td>
|
||||
@if ($requestableModel->isRequestedBy(Auth::user()))
|
||||
|
||||
@@ -230,7 +230,7 @@ View Assets for {{ $user->present()->fullName() }}
|
||||
id="table"
|
||||
data-cookie="false"
|
||||
data-cookie-id-table="userHistoryTable-{{ config('version.hash_version') }}"
|
||||
data-url="{{route('api.activity.list', ['user_id' => $user->id, 'order' => 'desc']) }}">
|
||||
data-url="{{route('api.activity.index', ['user_id' => $user->id, 'order' => 'desc']) }}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter"></th>
|
||||
|
||||
@@ -60,15 +60,21 @@
|
||||
@include ('partials.bootstrap-table', ['exportFile' => 'maintenances-export', 'search' => true])
|
||||
<script>
|
||||
function maintenanceActions(value, row) {
|
||||
|
||||
var actions = '<nobr>';
|
||||
if ((row) && (row.available_actions.update === true)) {
|
||||
actions += '<a href="{{ url('/') }}/hardware/maintenances/' + row.id + '/edit" class="btn btn-sm btn-warning" data-tooltip="true" title="Update"><i class="fa fa-pencil"></i></a> ';
|
||||
}
|
||||
actions += '</nobr>'
|
||||
if ((row) && (row.available_actions.delete === true)) {
|
||||
return '<a href="{{ url('/') }}/hardware/maintenances/' + row.id + '" '
|
||||
actions += '<a href="{{ url('/') }}/hardware/maintenances/' + row.id + '" '
|
||||
+ ' class="btn btn-danger btn-sm delete-asset" data-tooltip="true" '
|
||||
+ ' data-toggle="modal" '
|
||||
+ ' data-content="{{ trans('general.sure_to_delete') }} ' + row.name + '?" '
|
||||
+ ' data-title="{{ trans('general.delete') }}" onClick="return false;">'
|
||||
+ '<i class="fa fa-trash"></i></a></nobr>';
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
name="consumable_users"
|
||||
class="table table-striped snipe-table"
|
||||
id="table"
|
||||
data-url="{{route('api.consumables.show', $consumable->id)}}"
|
||||
data-url="{{route('api.consumables.showUsers', $consumable->id)}}"
|
||||
data-cookie="true"
|
||||
data-click-to-select="true"
|
||||
data-cookie-id-table="consumableDetailTable-{{ config('version.hash_version') }}"
|
||||
|
||||
@@ -44,11 +44,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Locations -->
|
||||
<div id="location_id" class="form-group{{ $errors->has('location_id') ? ' has-error' : '' }}">
|
||||
{{ Form::label('location_id', trans('general.location'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-9">
|
||||
{{ Form::select('location_id', $locations_list , Input::old('location_id'), array('class'=>'select2', 'id'=>'location_id', 'style'=>'width:100%')) }}
|
||||
|
||||
{!! $errors->first('location_id', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Next Audit -->
|
||||
<div class="form-group {{ $errors->has('next_audit_date') ? 'error' : '' }}">
|
||||
{{ Form::label('name', trans('admin/hardware/form.checkout_date'), array('class' => 'col-md-3 control-label')) }}
|
||||
{{ Form::label('name', trans('general.next_audit_date'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-9">
|
||||
<div class="input-group date col-md-5" data-provide="datepicker" data-date-format="yyyy-mm-dd">
|
||||
<input type="text" class="form-control" placeholder="{{ trans('general.next_audit_date') }}" name="next_audit_date" id="next_audit_date" value="{{ Input::old('next_audit_date', $next_audit_date) }}">
|
||||
@@ -73,7 +82,7 @@
|
||||
</div> <!--/.box-body-->
|
||||
<div class="box-footer">
|
||||
<a class="btn btn-link" href="{{ URL::previous() }}"> {{ trans('button.cancel') }}</a>
|
||||
<button type="submit" class="btn btn-success pull-right"><i class="fa fa-check icon-white"></i> {{ trans('general.checkout') }}</button>
|
||||
<button type="submit" class="btn btn-success pull-right"><i class="fa fa-check icon-white"></i> {{ trans('general.audit') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -37,33 +37,33 @@
|
||||
{!! $errors->first('assigned_to', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
<div class="col-md-1 col-sm-1 text-left">
|
||||
<a href='#' data-toggle="modal" data-target="#createModal" data-dependency="user" data-select='assigned_to' class="btn btn-sm btn-default">New</a>
|
||||
<a href='{{ route('modal.user') }}' data-toggle="modal" data-target="#createModal" data-dependency="user" data-select='assigned_to' class="btn btn-sm btn-default">New</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Checkout/Checkin Date -->
|
||||
<div class="form-group {{ $errors->has('checkout_at') ? 'error' : '' }}">
|
||||
{{ Form::label('name', trans('admin/hardware/form.checkout_date'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-4 input-group required">
|
||||
<input type="date" class="datepicker form-control" data-date-format="yyyy-mm-dd" name="checkout_at" id="checkout_at" value="{{ Input::old('checkout_at', date('Y-m-d')) }}">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
<!-- Checkout/Checkin Date -->
|
||||
<div class="form-group {{ $errors->has('checkout_at') ? 'error' : '' }}">
|
||||
{{ Form::label('name', trans('admin/hardware/form.checkout_date'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-8">
|
||||
<div class="input-group date col-md-5" data-provide="datepicker" data-date-format="yyyy-mm-dd">
|
||||
<input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="checkout_at" id="checkout_at" value="{{ Input::old('checkout_at') }}">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
</div>
|
||||
{!! $errors->first('checkout_at', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
{!! $errors->first('checkout_at', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Expected Checkin Date -->
|
||||
<div class="form-group {{ $errors->has('expected_checkin') ? 'error' : '' }}">
|
||||
{{ Form::label('name', trans('admin/hardware/form.expected_checkin'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-4 input-group">
|
||||
<input type="date" class="datepicker form-control" data-date-format="yyyy-mm-dd" name="expected_checkin" id="expected_checkin" value="{{ Input::old('expected_checkin') }}">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
<!-- Expected Checkin Date -->
|
||||
<div class="form-group {{ $errors->has('expected_checkin') ? 'error' : '' }}">
|
||||
{{ Form::label('name', trans('admin/hardware/form.expected_checkin'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-8">
|
||||
<div class="input-group date col-md-5" data-provide="datepicker" data-date-format="yyyy-mm-dd">
|
||||
<input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="expected_checkin" id="expected_checkin" value="{{ Input::old('expected_checkin') }}">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
</div>
|
||||
{!! $errors->first('expected_checkin', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
{!! $errors->first('expected_checkin', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Note -->
|
||||
@@ -107,121 +107,6 @@
|
||||
@stop
|
||||
|
||||
@section('moar_scripts')
|
||||
|
||||
{{-- Some room for the modals --}}
|
||||
<div class="modal fade" id="createModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Modal title</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-first_name">{{ trans('general.first_name') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12 required"><input type='text' id='modal-first_name' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-last_name">{{ trans('general.last_name') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12"><input type='text' id='modal-last_name' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-username">{{ trans('admin/users/table.username') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12 required"><input type='text' id='modal-username' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-email">{{ trans('admin/users/table.email') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12"><input type='email' id='modal-email' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-password">{{ trans('admin/users/table.password') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12 required"><input type='password' id='modal-password' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('button.cancel') }}</button>
|
||||
<button type="button" class="btn btn-primary" id="modal-save">{{ trans('general.save') }}</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Ajax call to retrieve user assets -->
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
var model,select;
|
||||
$('#createModal').on("show.bs.modal",function (event) {
|
||||
console.warn('modal ran');
|
||||
var link = $(event.relatedTarget);
|
||||
model=link.data("dependency");
|
||||
select=link.data("select");
|
||||
var modal = $(this);
|
||||
modal.find('.modal-title').text('Add a new ' + model);
|
||||
$('.dynamic-form-row').hide();
|
||||
function show_er(selector) {
|
||||
$(selector).parent().parent().show();
|
||||
}
|
||||
show_er('#modal-name');
|
||||
switch(model) {
|
||||
case 'user':
|
||||
$('.dynamic-form-row').hide(); //we don't want a generic "name"
|
||||
show_er("#modal-first_name");
|
||||
show_er("#modal-last_name");
|
||||
show_er("#modal-username");
|
||||
show_er("#modal-email");
|
||||
show_er("#modal-password");
|
||||
show_er("#modal-password_confirm");
|
||||
break;
|
||||
//do nothing, they just need 'name'
|
||||
}
|
||||
//console.warn("The Model is: "+model+" and the select is: "+select);
|
||||
});
|
||||
$('#modal-save').on('click',function () {
|
||||
var data={};
|
||||
//console.warn("We are about to SAVE!!! for model: "+model+" and select ID: "+select);
|
||||
$('.modal-body input:visible').each(function (index,elem) {
|
||||
//console.warn("["+index+"]: "+elem.id+" = "+$(elem).val());
|
||||
var bits=elem.id.split("-");
|
||||
if(bits[0]==="modal") {
|
||||
data[bits[1]]=$(elem).val();
|
||||
}
|
||||
});
|
||||
$('.modal-body select:visible').each(function (index,elem) {
|
||||
var bits=elem.id.split("-");
|
||||
data[bits[1]]=$(elem).val();
|
||||
});
|
||||
data._token = '{{ csrf_token() }}',
|
||||
// console.dir(data);
|
||||
$.post("{{url('/') }}/api/"+model+"s",data,function (result) {
|
||||
var id=result.id;
|
||||
var name=result.name || (result.first_name+" "+result.last_name);
|
||||
$('.modal-body input:visible').val("");
|
||||
$('#createModal').modal('hide');
|
||||
//console.warn("The select ID thing we're going for is: "+select);
|
||||
var selector=document.getElementById(select);
|
||||
selector.options[selector.length] = new Option(name,id);
|
||||
selector.selectedIndex=selector.length-1;
|
||||
$(selector).trigger("change");
|
||||
}).fail(function (result) {
|
||||
//console.dir(result.responseJSON);
|
||||
msg=result.responseJSON.error.message || result.responseJSON.error;
|
||||
window.alert("Unable to add new "+model+" - error: "+msg);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
$('#assigned_to').on("change",function () {
|
||||
@@ -256,4 +141,4 @@ $(function() {
|
||||
});
|
||||
</script>
|
||||
|
||||
@stop
|
||||
@stop
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
</td>
|
||||
<td>
|
||||
@if ($asset->assignedTo)
|
||||
{{ $asset->assignedTo->present()->name().' ' .$asset->assigneduser ? '('.$asset->assigneduser->username. ')' : ''}}
|
||||
{{ $asset->assignedTo->present()->name()}}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -49,39 +49,35 @@
|
||||
<div id="assigned_user" class="form-group{{ $errors->has('assigned_to') ? ' has-error' : '' }}">
|
||||
{{ Form::label('assigned_user', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-7 required">
|
||||
{{ Form::select('assigned_user', $users_list , Input::old('assigned_user', $asset->assigned_type == 'App\Models\User' ? $asset->assigned_to : 0), array('class'=>'select2', 'id'=>'assigned_user', 'style'=>'width:100%')) }}
|
||||
{{ Form::select('assigned_user', $users_list , Input::old('assigned_user', $asset->assigned_type == 'App\Models\User' ? $asset->assigned_to : 0), array('class'=>'select2', 'id'=>'assigned_user_select', 'style'=>'width:100%')) }}
|
||||
|
||||
{!! $errors->first('assigned_user', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
<div class="col-md-1 col-sm-1 text-left">
|
||||
@can('create', \App\Models\User::class)
|
||||
<a href='#' data-toggle="modal" data-target="#createModal" data-dependency="user" data-select='assigned_user' class="btn btn-sm btn-default">New</a>
|
||||
<a href='{{ route('modal.user') }}' data-toggle="modal" data-target="#createModal" data-dependency="user" data-select='assigned_user_select' class="btn btn-sm btn-default">New</a>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
@if (!$asset->requireAcceptance())
|
||||
<!-- Assets -->
|
||||
<div id="assigned_asset" class="form-group{{ $errors->has('assigned_to') ? ' has-error' : '' }}">
|
||||
{{ Form::label('assigned_asset', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-7 required">
|
||||
{{ Form::select('assigned_asset', $assets_list , Input::old('assigned_asset', $asset->assigned_type == 'App\Models\Asset' ? $asset->assigned_to : 0), array('class'=>'select2', 'id'=>'assigned_asset', 'style'=>'width:100%')) }}
|
||||
{!! $errors->first('assigned_asset', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Assets -->
|
||||
<div id="assigned_asset" class="form-group{{ $errors->has('assigned_to') ? ' has-error' : '' }}">
|
||||
{{ Form::label('assigned_asset', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-7 required">
|
||||
{{ Form::select('assigned_asset', $assets_list , Input::old('assigned_asset', $asset->assigned_type == 'App\Models\Asset' ? $asset->assigned_to : 0), array('class'=>'select2', 'id'=>'assigned_asset', 'style'=>'width:100%')) }}
|
||||
|
||||
{!! $errors->first('assigned_asset', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Locations -->
|
||||
<div id="assigned_location" class="form-group{{ $errors->has('assigned_to') ? ' has-error' : '' }}">
|
||||
{{ Form::label('assigned_location', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-7 required">
|
||||
{{ Form::select('assigned_location', $locations_list , Input::old('assigned_location', $asset->assigned_type == 'App\Models\Asset' ? $asset->assigned_to : 0), array('class'=>'select2', 'id'=>'assigned_location', 'style'=>'width:100%')) }}
|
||||
|
||||
{!! $errors->first('assigned_location', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Locations -->
|
||||
<div id="assigned_location" class="form-group{{ $errors->has('assigned_to') ? ' has-error' : '' }}">
|
||||
{{ Form::label('assigned_location', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-7 required">
|
||||
{{ Form::select('assigned_location', $locations_list , Input::old('assigned_location', $asset->assigned_type == 'App\Models\Asset' ? $asset->assigned_to : 0), array('class'=>'select2', 'id'=>'assigned_location', 'style'=>'width:100%')) }}
|
||||
{!! $errors->first('assigned_location', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<!-- Checkout/Checkin Date -->
|
||||
<div class="form-group {{ $errors->has('checkout_at') ? 'error' : '' }}">
|
||||
{{ Form::label('name', trans('admin/hardware/form.checkout_date'), array('class' => 'col-md-3 control-label')) }}
|
||||
@@ -158,179 +154,49 @@
|
||||
@stop
|
||||
|
||||
@section('moar_scripts')
|
||||
|
||||
{{-- Some room for the modals --}}
|
||||
<div class="modal fade" id="createModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Modal title</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-first_name">{{ trans('general.first_name') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12 required"><input type='text' id='modal-first_name' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-last_name">{{ trans('general.last_name') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12"><input type='text' id='modal-last_name' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-username">{{ trans('admin/users/table.username') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12 required"><input type='text' id='modal-username' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-email">{{ trans('admin/users/table.email') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12"><input type='email' id='modal-email' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-password">{{ trans('admin/users/table.password') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12 required"><input type='password' id='modal-password' class="form-control"></div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('button.cancel') }}</button>
|
||||
<button type="button" class="btn btn-primary" id="modal-save">{{ trans('general.save') }}</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Ajax call to retrieve user assets -->
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
$(function () {
|
||||
var model,select;
|
||||
|
||||
|
||||
$('#createModal').on("show.bs.modal",function (event) {
|
||||
console.warn('modal ran');
|
||||
var link = $(event.relatedTarget);
|
||||
model=link.data("dependency");
|
||||
select=link.data("select");
|
||||
|
||||
var modal = $(this);
|
||||
modal.find('.modal-title').text('Add a new ' + model);
|
||||
|
||||
$('.dynamic-form-row').hide();
|
||||
function show_er(selector) {
|
||||
$(selector).parent().parent().show();
|
||||
}
|
||||
show_er('#modal-name');
|
||||
switch(model) {
|
||||
|
||||
case 'user':
|
||||
$('.dynamic-form-row').hide(); //we don't want a generic "name"
|
||||
show_er("#modal-first_name");
|
||||
show_er("#modal-last_name");
|
||||
show_er("#modal-username");
|
||||
show_er("#modal-email");
|
||||
show_er("#modal-password");
|
||||
show_er("#modal-password_confirm");
|
||||
break;
|
||||
|
||||
|
||||
//do nothing, they just need 'name'
|
||||
}
|
||||
|
||||
//console.warn("The Model is: "+model+" and the select is: "+select);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$('#modal-save').on('click',function () {
|
||||
var data={};
|
||||
//console.warn("We are about to SAVE!!! for model: "+model+" and select ID: "+select);
|
||||
$('.modal-body input:visible').each(function (index,elem) {
|
||||
//console.warn("["+index+"]: "+elem.id+" = "+$(elem).val());
|
||||
var bits=elem.id.split("-");
|
||||
if(bits[0]==="modal") {
|
||||
data[bits[1]]=$(elem).val();
|
||||
}
|
||||
});
|
||||
$('.modal-body select:visible').each(function (index,elem) {
|
||||
var bits=elem.id.split("-");
|
||||
data[bits[1]]=$(elem).val();
|
||||
});
|
||||
|
||||
data._token = '{{ csrf_token() }}',
|
||||
// console.dir(data);
|
||||
|
||||
$.post("{{url('/') }}/api/"+model+"s",data,function (result) {
|
||||
var id=result.id;
|
||||
var name=result.name || (result.first_name+" "+result.last_name);
|
||||
$('.modal-body input:visible').val("");
|
||||
$('#createModal').modal('hide');
|
||||
|
||||
//console.warn("The select ID thing we're going for is: "+select);
|
||||
var selector=document.getElementById(select);
|
||||
selector.options[selector.length] = new Option(name,id);
|
||||
selector.selectedIndex=selector.length-1;
|
||||
$(selector).trigger("change");
|
||||
|
||||
|
||||
}).fail(function (result) {
|
||||
//console.dir(result.responseJSON);
|
||||
msg=result.responseJSON.error.message || result.responseJSON.error;
|
||||
window.alert("Unable to add new "+model+" - error: "+msg);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
$(function() {
|
||||
$('#assigned_to').on("change",function () {
|
||||
// console.warn("Model Id has changed!");
|
||||
var userid=$('#assigned_to').val();
|
||||
$('#assigned_user').on("change",function () {
|
||||
var userid = $('#assigned_user option:selected').val();
|
||||
if(userid=='') {
|
||||
console.warn('no user selected');
|
||||
$('#current_assets_box').fadeOut();
|
||||
$('#current_assets_content').html("");
|
||||
} else {
|
||||
|
||||
$.get("{{url('/') }}/api/users/"+userid+"/assets",{_token: "{{ csrf_token() }}"},function (data) {
|
||||
// console.warn("Ajax call came back okay for user " + userid + "! " + data.length + " Data is: "+data);
|
||||
if (data.length > 0) {
|
||||
$('#current_assets_box').fadeIn();
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '{{url('/') }}/api/v1/users/' + userid + '/assets',
|
||||
headers: {
|
||||
"X-Requested-With": 'XMLHttpRequest',
|
||||
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
|
||||
var table_html = '<div class="row"><div class="col-md-12"><table class="table table-striped"><thead><tr><td>{{ trans('admin/hardware/form.name') }}</td><td>{{ trans('admin/hardware/form.tag') }}</td></tr></thead><tbody>';
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
$('#current_assets_box').fadeIn();
|
||||
|
||||
$('#current_assets_content').append('');
|
||||
var table_html = '<div class="row"><div class="col-md-12"><table class="table table-striped"><thead><tr><td>{{ trans('admin/hardware/form.name') }}</td><td>{{ trans('admin/hardware/form.tag') }}</td></tr></thead><tbody>';
|
||||
|
||||
for (var i in data) {
|
||||
var asset = data[i];
|
||||
table_html += "<tr><td class=\"col-md-8\"><a href=\"{{ url('/') }}/hardware/" + asset.id + "/view\">" + asset.name;
|
||||
if (asset.model.name!='') {
|
||||
table_html += " (" + asset.model.name + ")";
|
||||
$('#current_assets_content').append('');
|
||||
|
||||
for (var i in data) {
|
||||
var asset = data[i];
|
||||
table_html += '<tr><td class="col-md-8"><a href="{{ url('/') }}/hardware/' + asset.id + '">' + asset.name;
|
||||
if (asset.model.name!='') {
|
||||
table_html += " (" + asset.model.name + ")";
|
||||
|
||||
}
|
||||
table_html += "</a></td><td class=\"col-md-4\">" + asset.asset_tag + "</td></tr>";
|
||||
}
|
||||
table_html += "</a></td><td class=\"col-md-4\">" + asset.asset_tag + "</td></tr>";
|
||||
|
||||
$('#current_assets_content').html(table_html + '</tbody></table></div></div>');
|
||||
|
||||
},
|
||||
error: function (data) {
|
||||
$('#current_assets_box').fadeOut();
|
||||
}
|
||||
|
||||
$('#current_assets_content').html(table_html + '</tbody></table></div></div>');
|
||||
|
||||
} else {
|
||||
$('#current_assets_box').fadeOut();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -160,9 +160,6 @@
|
||||
@stop
|
||||
|
||||
@section('moar_scripts')
|
||||
{{-- Some room for the modals --}}
|
||||
<div class="modal fade" id="createModal">
|
||||
</div><!-- /.modal -->
|
||||
<script>
|
||||
|
||||
|
||||
@@ -230,21 +227,6 @@
|
||||
user_add($(".status_id").val());
|
||||
});
|
||||
|
||||
//handle modal-add-interstitial calls
|
||||
var model, select;
|
||||
|
||||
$('#createModal').on("show.bs.modal", function (event) {
|
||||
var link = $(event.relatedTarget);
|
||||
model = link.data("dependency");
|
||||
select = link.data("select");
|
||||
// console.warn("Uh, href is: "+link.attr('href'));
|
||||
// console.dir(link);
|
||||
$('#createModal').load(link.attr('href'),function () {
|
||||
//do we need to re-select2 this, after load? Probably.
|
||||
$('#createModal').find('select.select2').select2();
|
||||
});
|
||||
});
|
||||
|
||||
$("form").submit(function (event) {
|
||||
event.preventDefault();
|
||||
return sendForm();
|
||||
@@ -370,98 +352,6 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$('#createModal').on('click','#modal-save', function () {
|
||||
console.warn("MODAL SAVE CALLED FOR MODAL!");
|
||||
var data = {};
|
||||
console.warn("We are about to SAVE!!! for model: "+model+" and select ID: "+select);
|
||||
$('.modal-body input:visible').each(function (index, elem) {
|
||||
console.warn("["+index+"]: "+elem.id+" = "+$(elem).val());
|
||||
var bits = elem.id.split("-");
|
||||
if (bits[0] === "modal") {
|
||||
data[bits[1]] = $(elem).val();
|
||||
}
|
||||
});
|
||||
//this can probably get replaced with a normal 'serialize' instead
|
||||
$('.modal-body select:visible').each(function (index, elem) {
|
||||
var bits = elem.id.split("-");
|
||||
data[bits[1]] = $(elem).val();
|
||||
});
|
||||
|
||||
data._token = '{{ csrf_token() }}';
|
||||
console.log(data);
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: "{{ url('/') }}/api/v1/" + model + "s",
|
||||
headers: {
|
||||
"X-Requested-With": 'XMLHttpRequest',
|
||||
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
|
||||
data: data,
|
||||
success: function (result) {
|
||||
// {"status":"error","messages":{"name":["The name field is required."]}}
|
||||
if(result.status == "error") {
|
||||
var error_message="";
|
||||
for(var field in result.messages) {
|
||||
error_message+="Problem(s) with field '"+field+"': "+result.messages[field].join(", ");
|
||||
}
|
||||
//window.alert("Error adding "+model+": "+error_message);
|
||||
$('#modal_error_msg').html(error_message).show();
|
||||
return false;
|
||||
}
|
||||
var id = result.payload.id;
|
||||
var name = result.payload.name || (result.payload.first_name + " " + result.payload.last_name);
|
||||
console.log(name);
|
||||
$('#createModal').modal('hide');
|
||||
$('#createModal').html("");
|
||||
|
||||
// "select" is the original drop-down menu that someone
|
||||
// clicked 'add' on to add a new 'thing'
|
||||
// this code adds the newly created object to that select
|
||||
var selector = document.getElementById(select);
|
||||
//console.log(document.getElementById(select));
|
||||
selector.options[selector.length] = new Option(name, id);
|
||||
selector.selectedIndex = selector.length - 1;
|
||||
$(selector).trigger("change");
|
||||
fetchCustomFields();
|
||||
|
||||
},
|
||||
error: function (result) {
|
||||
// console.log('Error: ' + result.responseJSON.error.message );
|
||||
msg = result.responseJSON.messages || result.responseJSON.error;
|
||||
$('#modal_error_msg').html("Server Error: "+msg).show();
|
||||
//window.alert("Unable to add new " + model + " - error: " + msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="{{ asset('js/pGenerator.jquery.js') }}"></script>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$('#genPassword').pGenerator({
|
||||
'bind': 'click',
|
||||
'passwordElement': '#modal-password',
|
||||
'displayElement': '#generated-password',
|
||||
'passwordLength': 16,
|
||||
'uppercase': true,
|
||||
'lowercase': true,
|
||||
'numbers': true,
|
||||
'specialChars': true,
|
||||
'onPasswordGenerated': function (generatedPassword) {
|
||||
$('#modal-password_confirm').val($('#modal-password').val());
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@stop
|
||||
|
||||
@@ -334,12 +334,12 @@
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
@if (($asset->assigneduser) && ($asset->assigned_to > 0) && ($asset->deleted_at==''))
|
||||
@if (($asset->checkedOutToUser()) && ($asset->assigned_to > 0) && ($asset->deleted_at==''))
|
||||
{{-- @TODO This should be extnded for details about non users --}}
|
||||
<h6><br>{{ trans('admin/hardware/form.checkedout_to') }}</h6>
|
||||
<ul>
|
||||
<li>
|
||||
<img src="{{ $asset->assigneduser->present()->gravatar() }}" class="img-circle" style="width: 100px; margin-right: 20px;" /><br /><br />
|
||||
<img src="{{ $asset->assignedTo->present()->gravatar() }}" class="img-circle" style="width: 100px; margin-right: 20px;" /><br /><br />
|
||||
</li>
|
||||
<li>
|
||||
{{ $asset->assignedTo->present()->nameUrl() }}
|
||||
@@ -357,12 +357,12 @@
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if (isset($asset->assigneduser->email))
|
||||
<li><br /><i class="fa fa-envelope-o"></i> <a href="mailto:{{ $asset->assigneduser->email }}">{{ $asset->assigneduser->email }}</a></li>
|
||||
@if (isset($asset->assignedTo->email))
|
||||
<li><br /><i class="fa fa-envelope-o"></i> <a href="mailto:{{ $asset->assignedTo->email }}">{{ $asset->assignedTo->email }}</a></li>
|
||||
@endif
|
||||
|
||||
@if ((isset($asset->assigneduser->phone)) && ($asset->assigneduser->phone!=''))
|
||||
<li><i class="fa fa-phone"></i> {{ $asset->assigneduser->phone }}</li>
|
||||
@if ((isset($asset->assignedTo->phone)) && ($asset->assignedTo->phone!=''))
|
||||
<li><i class="fa fa-phone"></i> {{ $asset->assignedTo->phone }}</li>
|
||||
@endif
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
192
resources/views/hardware/quickscan.blade.php
Normal file
192
resources/views/hardware/quickscan.blade.php
Normal file
@@ -0,0 +1,192 @@
|
||||
@extends('layouts/default')
|
||||
|
||||
{{-- Page title --}}
|
||||
@section('title')
|
||||
{{ trans('general.bulkaudit') }}
|
||||
@parent
|
||||
@stop
|
||||
|
||||
{{-- Page content --}}
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
|
||||
.input-group {
|
||||
padding-left: 0px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="row">
|
||||
{{ Form::open(['method' => 'POST', 'class' => 'form-horizontal', 'role' => 'form', 'id' => 'audit-form' ]) }}
|
||||
<!-- left column -->
|
||||
<div class="col-md-6">
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"> {{ trans('general.bulkaudit') }} </h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{{csrf_field()}}
|
||||
|
||||
<!-- Next Audit -->
|
||||
<div class="form-group {{ $errors->has('asset_tag') ? 'error' : '' }}">
|
||||
{{ Form::label('asset_tag', trans('general.asset_tag'), array('class' => 'col-md-3 control-label', 'id' => 'audit_tag')) }}
|
||||
<div class="col-md-9">
|
||||
<div class="input-group date col-md-5" data-date-format="yyyy-mm-dd">
|
||||
<input type="text" class="form-control" name="asset_tag" id="asset_tag" value="{{ Input::old('asset_tag') }}">
|
||||
|
||||
</div>
|
||||
{!! $errors->first('asset_tag', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Locations -->
|
||||
<div id="location_id" class="form-group{{ $errors->has('location_id') ? ' has-error' : '' }}">
|
||||
{{ Form::label('location_id', trans('general.location'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-9">
|
||||
{{ Form::select('location_id', $locations_list , Input::old('location_id'), array('class'=>'select2', 'id'=>'location_id', 'style'=>'width:100%')) }}
|
||||
|
||||
{!! $errors->first('location_id', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Next Audit -->
|
||||
<div class="form-group {{ $errors->has('next_audit_date') ? 'error' : '' }}">
|
||||
{{ Form::label('next_audit_date', trans('general.next_audit_date'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-9">
|
||||
<div class="input-group date col-md-5" data-provide="datepicker" data-date-format="yyyy-mm-dd">
|
||||
<input type="text" class="form-control" placeholder="{{ trans('general.next_audit_date') }}" name="next_audit_date" id="next_audit_date" value="{{ Input::old('next_audit_date', $next_audit_date) }}">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
</div>
|
||||
{!! $errors->first('next_audit_date', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Note -->
|
||||
<div class="form-group {{ $errors->has('note') ? 'error' : '' }}">
|
||||
{{ Form::label('note', trans('admin/hardware/form.notes'), array('class' => 'col-md-3 control-label')) }}
|
||||
<div class="col-md-8">
|
||||
<textarea class="col-md-6 form-control" id="note" name="note">{{ Input::old('note') }}</textarea>
|
||||
{!! $errors->first('note', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div> <!--/.box-body-->
|
||||
<div class="box-footer">
|
||||
<a class="btn btn-link" href="{{ route('hardware.index') }}"> {{ trans('button.cancel') }}</a>
|
||||
<button type="submit" id="audit_button" class="btn btn-success pull-right"><i class="fa fa-check icon-white"></i> {{ trans('general.audit') }}</button>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{{Form::close()}}
|
||||
</div> <!--/.col-md-7-->
|
||||
<div class="col-md-6">
|
||||
<div class="box box-default" id="audited-div" style="display: none">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"> {{ trans('general.bulkaudit_status') }} (<span id="audit-counter">0</span> assets audited) </h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
|
||||
<table id="audited" class="table table-striped snipe-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ trans('general.asset_tag') }}</th>
|
||||
<th>{{ trans('general.bulkaudit_status') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id="audit-loader" style="display: none;">
|
||||
<td colspan="3">
|
||||
<i class="fa fa-spinner spin" aria-hidden="true"></i> Processing...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
|
||||
@section('moar_scripts')
|
||||
<script>
|
||||
|
||||
$("#audit-form").submit(function (event) {
|
||||
$('#audited-div').show();
|
||||
$('#audit-loader').show();
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#audit-form").get(0);
|
||||
var formData = $('#audit-form').serializeArray();
|
||||
|
||||
$.ajax({
|
||||
url: "{{ route('api.asset.audit') }}",
|
||||
type : 'POST',
|
||||
headers: {
|
||||
"X-Requested-With": 'XMLHttpRequest',
|
||||
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
dataType : 'json',
|
||||
data : formData,
|
||||
success : function (data) {
|
||||
if (data.status == 'success') {
|
||||
$('#audited tbody').append("<tr class='success'><td>" + data.payload.asset_tag + "</td><td>" + data.messages + "</td><td><i class='fa fa-check text-success'></i></td></tr>");
|
||||
incrementOnSuccess();
|
||||
} else {
|
||||
handleAuditFail(data);
|
||||
}
|
||||
|
||||
},
|
||||
error: function (data) {
|
||||
handleAuditFail(data);
|
||||
},
|
||||
complete: function() {
|
||||
$('#audit-loader').hide();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
function handleAuditFail (data) {
|
||||
if (data.asset_tag) {
|
||||
var asset_tag = data.asset_tag;
|
||||
} else {
|
||||
var asset_tag = '';
|
||||
}
|
||||
if (data.messages) {
|
||||
var messages = data.messages;
|
||||
} else {
|
||||
var messages = '';
|
||||
}
|
||||
$('#audited tbody').append("<tr class='danger'><td>" + asset_tag + "</td><td>" + messages + "</td><td><i class='fa fa-times text-danger'></i></td></tr>");
|
||||
}
|
||||
|
||||
function incrementOnSuccess() {
|
||||
var x = parseInt($('#audit-counter').html());
|
||||
y = x + 1;
|
||||
$('#audit-counter').html(y);
|
||||
}
|
||||
|
||||
$("#audit_tag").focus();
|
||||
|
||||
</script>
|
||||
@stop
|
||||
@@ -401,19 +401,19 @@
|
||||
@if (($asset->assignedTo) && ($asset->deleted_at==''))
|
||||
<h4>{{ trans('admin/hardware/form.checkedout_to') }}</h4>
|
||||
<p>
|
||||
@if($asset->assigned_type == User::class) <!-- Only users have avatars currently-->
|
||||
<img src="{{ $asset->assignedTo->present()->gravatar() }}" class="user-image-inline" alt="{{ $asset->assigneduser->present()->fullName() }}">
|
||||
@if($asset->checkedOutToUser()) <!-- Only users have avatars currently-->
|
||||
<img src="{{ $asset->assignedTo->present()->gravatar() }}" class="user-image-inline" alt="{{ $asset->assignedTo->present()->fullName() }}">
|
||||
@endif
|
||||
{!! $asset->assignedTo->present()->glyph() . ' ' .$asset->assignedTo->present()->nameUrl() !!}
|
||||
</p>
|
||||
|
||||
<ul class="list-unstyled">
|
||||
@if ((isset($asset->assigneduser->email)) && ($asset->assigneduser->email!=''))
|
||||
<li><i class="fa fa-envelope-o"></i> <a href="mailto:{{ $asset->assigneduser->email }}">{{ $asset->assigneduser->email }}</a></li>
|
||||
@if ((isset($asset->assignedTo->email)) && ($asset->assignedTo->email!=''))
|
||||
<li><i class="fa fa-envelope-o"></i> <a href="mailto:{{ $asset->assignedTo->email }}">{{ $asset->assignedTo->email }}</a></li>
|
||||
@endif
|
||||
|
||||
@if ((isset($asset->assigneduser->phone)) && ($asset->assigneduser->phone!=''))
|
||||
<li><i class="fa fa-phone"></i> {{ $asset->assigneduser->phone }}</li>
|
||||
@if ((isset($asset->assignedTo->phone)) && ($asset->assignedTo->phone!=''))
|
||||
<li><i class="fa fa-phone"></i> {{ $asset->assignedTo->phone }}</li>
|
||||
@endif
|
||||
|
||||
@if (isset($asset->assetLoc))
|
||||
@@ -661,7 +661,7 @@
|
||||
</td>
|
||||
<td>
|
||||
@if ( \App\Helpers\Helper::checkUploadIsImage($file->get_src('assets')))
|
||||
<a href="../{{ $asset->id }}/showfile/{{ $file->id }}" data-toggle="lightbox" data-type="image"><img src="../{{ $asset->id }}/showfile/{{ $file->id }}"" class="img-thumbnail" style="max-width: 50px;"></a>
|
||||
<a href="{{ route('show/assetfile', ['assetId' => $asset->id, 'fileId' =>$file->id]) }}" data-toggle="lightbox" data-type="image"><img src="{{ route('show/assetfile', ['assetId' => $asset->id, 'fileId' =>$file->id]) }}" class="img-thumbnail" style="max-width: 50px;"></a>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -111,12 +111,16 @@
|
||||
<li class="left-navblock">
|
||||
@if ($snipeSettings->brand == '3')
|
||||
<a class="logo navbar-brand no-hover" href="{{ url('/') }}">
|
||||
@if ($snipeSettings->logo!='')
|
||||
<img class="navbar-brand-img" src="{{ url('/') }}/uploads/{{ $snipeSettings->logo }}">
|
||||
@endif
|
||||
{{ $snipeSettings->site_name }}
|
||||
</a>
|
||||
@elseif ($snipeSettings->brand == '2')
|
||||
<a class="logo navbar-brand no-hover" href="{{ url('/') }}">
|
||||
@if ($snipeSettings->logo!='')
|
||||
<img class="navbar-brand-img" src="{{ url('/') }}/uploads/{{ $snipeSettings->logo }}">
|
||||
@endif
|
||||
</a>
|
||||
@else
|
||||
<a class="logo no-hover" href="{{ url('/') }}">
|
||||
@@ -253,7 +257,7 @@
|
||||
@for($i=0; count($alert_items) > $i; $i++)
|
||||
|
||||
<li><!-- Task item -->
|
||||
<a href="{{ url('/') }}/{{ $alert_items[$i]['type'] }}/{{ $alert_items[$i]['id'] }}/view">
|
||||
<a href="{{route($alert_items[$i]['type'].'.show', $alert_items[$i]['id'])}}">
|
||||
<h3>{{ $alert_items[$i]['name'] }}
|
||||
<small class="pull-right">
|
||||
{{ $alert_items[$i]['remaining'] }} remaining
|
||||
@@ -410,6 +414,9 @@
|
||||
<li><a href="{{ route('maintenances.index') }}">@lang('general.asset_maintenances') </a></li>
|
||||
<li><a href="{{ url('hardware/history') }}">@lang('general.import-history') </a></li>
|
||||
@endcan
|
||||
@can('audit', \App\Models\Asset::class)
|
||||
<li><a href="{{ route('assets.bulkaudit') }}">@lang('general.bulkaudit') </a></li>
|
||||
@endcan
|
||||
</ul>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">{{ trans('general.location') }}</h4>
|
||||
<h4 class="modal-title">{{ trans('admin/locations/table.create') }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-danger" id="modal_error_msg" style="display:none">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">{{ trans('general.model') }}</h4>
|
||||
<h4 class="modal-title">{{ trans('admin/models/table.create') }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-danger" id="modal_error_msg" style="display:none">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">{{ trans('admin/hardware/form.status') }}</h4>
|
||||
<h4 class="modal-title">{{ trans('admin/statuslabels/table.create') }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-danger" id="modal_error_msg" style="display:none">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">{{ trans('general.supplier') }}</h4>
|
||||
<h4 class="modal-title">{{ trans('admin/suppliers/table.create') }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-danger" id="modal_error_msg" style="display:none">
|
||||
|
||||
@@ -1,8 +1,29 @@
|
||||
|
||||
<script src="/js/pGenerator.jquery.js"></script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
|
||||
$('#genPassword').pGenerator({
|
||||
'bind': 'click',
|
||||
'passwordElement': '#modal-password',
|
||||
'displayElement': '#generated-password',
|
||||
'passwordLength': 16,
|
||||
'uppercase': true,
|
||||
'lowercase': true,
|
||||
'numbers': true,
|
||||
'specialChars': true,
|
||||
'onPasswordGenerated': function (generatedPassword) {
|
||||
$('#modal-password_confirm').val($('#modal-password').val());
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">{{ trans('general.user') }}</h4>
|
||||
<h4 class="modal-title">{{ trans('admin/users/table.createuser') }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-danger" id="modal_error_msg" style="display:none">
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<th data-sortable="true" data-field="name" data-searchable="true" data-formatter="hardwareLinkFormatter">{{ trans('general.name') }}</th>
|
||||
<th data-sortable="true" data-field="asset_tag" data-formatter="hardwareLinkFormatter">{{ trans('general.asset_tag') }}</th>
|
||||
<th data-sortable="true" data-field="serial" data-formatter="hardwareLinkFormatter">{{ trans('admin/hardware/table.serial') }}</th>
|
||||
<th data-sortable="false" data-field="assigned_to" data-formatter="usersLinkObjFormatter">{{ trans('general.user') }}</th>
|
||||
<th data-sortable="false" data-field="assigned_to" data-formatter="polymorphicItemFormatter">{{ trans('general.user') }}</th>
|
||||
<th data-sortable="false" data-field="inout" data-formatter="hardwareInOutFormatter">{{ trans('admin/hardware/table.change') }}</th>
|
||||
<th data-switchable="false" data-searchable="false" data-sortable="false" data-field="actions" data-formatter="hardwareActionsFormatter">{{ trans('table.actions') }}</th>
|
||||
</tr>
|
||||
|
||||
@@ -98,6 +98,15 @@ $('.snipe-table').bootstrapTable({
|
||||
|
||||
});
|
||||
|
||||
|
||||
function dateRowCheckStyle(value) {
|
||||
if ((value.days_to_next_audit) && (value.days_to_next_audit < {{ $snipeSettings->audit_warning_days ?: 0 }})) {
|
||||
return { classes : "danger" }
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
// Handle whether or not the edit button should be disabled
|
||||
$('.snipe-table').on('check.bs.table', function () {
|
||||
$('#bulkEdit').removeAttr('disabled');
|
||||
@@ -183,6 +192,8 @@ $('.snipe-table').bootstrapTable({
|
||||
item_destination = 'licenses';
|
||||
} else if (value.type == 'user') {
|
||||
item_destination = 'users';
|
||||
} else if (value.type == 'location') {
|
||||
item_destination = 'locations'
|
||||
}
|
||||
|
||||
return '<a href="{{ url('/') }}/' + item_destination +'/' + value.id + '"> ' + value.name + '</a>';
|
||||
|
||||
@@ -15,22 +15,25 @@
|
||||
<div class="box-body">
|
||||
|
||||
<table
|
||||
name="activityReport"
|
||||
name="auditReport"
|
||||
data-toolbar="#toolbar"
|
||||
class="table table-striped snipe-table"
|
||||
id="table"
|
||||
data-url="{{ route('api.activity.index', ['action_type' => 'audit']) }}"
|
||||
data-cookie="true"
|
||||
data-cookie-id-table="activityReportTable">
|
||||
data-cookie-id-table="activityReportTable"
|
||||
data-row-style="dateRowCheckStyle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter"></th>
|
||||
<th class="col-sm-3" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
|
||||
<th class="col-sm-1" data-field="image" data-visible="false" data-formatter="imageFormatter">{{ trans('admin/hardware/table.image') }}</th>
|
||||
<th class="col-sm-2" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.audit') }}</th>
|
||||
<th class="col-sm-2" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
|
||||
<th class="col-sm-2" data-field="action_type">{{ trans('general.action') }}</th>
|
||||
<th class="col-sm-3" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
|
||||
<th class="col-sm-2" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
|
||||
<th class="col-sm-1" data-field="location" data-formatter="locationsLinkObjFormatter">{{ trans('general.location') }}</th>
|
||||
<th class="col-sm-2" data-field="next_audit_date" data-formatter="dateDisplayFormatter">{{ trans('general.next_audit_date') }}</th>
|
||||
<th class="col-sm-1" data-field="days_to_next_audit">{{ trans('general.days_to_next_audit') }}</th>
|
||||
|
||||
<th class="col-sm-1" data-field="note">{{ trans('general.notes') }}</th>
|
||||
<th class="col-sm-2" data-field="note">{{ trans('general.notes') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
@@ -42,5 +45,5 @@
|
||||
|
||||
|
||||
@section('moar_scripts')
|
||||
@include ('partials.bootstrap-table', ['exportFile' => 'activity-export', 'search' => true])
|
||||
@include ('partials.bootstrap-table', ['exportFile' => 'audit-export', 'search' => false])
|
||||
@stop
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if (($asset->assignedTo) && ($asset->assigneduser->assetLoc))
|
||||
@if (($asset->checkedOutToUser()) && ($asset->assignedTo->assetLoc))
|
||||
{{ $asset->assignedTo->assetLoc->city }}, {{ $asset->assignedTo->assetLoc->state}}
|
||||
@endif
|
||||
</td>
|
||||
|
||||
@@ -90,6 +90,41 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Alert interval -->
|
||||
<div class="form-group {{ $errors->has('audit_interval') ? 'error' : '' }}">
|
||||
<div class="col-md-3">
|
||||
{{ Form::label('audit_interval', trans('admin/settings/general.audit_interval')) }}
|
||||
</div>
|
||||
<div class="input-group col-md-2">
|
||||
{{ Form::text('audit_interval', Input::old('audit_interval', $setting->audit_interval), array('class' => 'form-control','placeholder' => '12', 'maxlength'=>'3', 'style'=>'width: 60px;')) }}
|
||||
<span class="input-group-addon">{{ trans('general.months') }}</span>
|
||||
</div>
|
||||
<div class="col-md-9 col-md-offset-3">
|
||||
{!! $errors->first('audit_interval', '<span class="alert-msg">:message</span>') !!}
|
||||
<p class="help-block">{{ trans('admin/settings/general.audit_interval_help') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alert threshold -->
|
||||
<div class="form-group {{ $errors->has('audit_warning_days') ? 'error' : '' }}">
|
||||
<div class="col-md-3">
|
||||
{{ Form::label('audit_warning_days', trans('admin/settings/general.audit_warning_days')) }}
|
||||
</div>
|
||||
<div class="input-group col-md-2">
|
||||
{{ Form::text('audit_warning_days', Input::old('audit_warning_days', $setting->audit_warning_days), array('class' => 'form-control','placeholder' => '14', 'maxlength'=>'3', 'style'=>'width: 60px;')) }}
|
||||
<span class="input-group-addon">{{ trans('general.days') }}</span>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-md-9 col-md-offset-3">
|
||||
{!! $errors->first('audit_warning_days', '<span class="alert-msg">:message</span>') !!}
|
||||
<p class="help-block">{{ trans('admin/settings/general.audit_warning_days_help') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div> <!--/.box-body-->
|
||||
|
||||
@@ -49,18 +49,18 @@
|
||||
@foreach ($supplier->assets as $supplierassets)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('suppliers.show', $supplierassets->id) }}">
|
||||
<a href="{{ route('hardware.show', $supplierassets->id) }}">
|
||||
{{ $supplierassets->asset_tag }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('suppliers.show', $supplierassets->id) }}">
|
||||
<a href="{{ route('hardware.show', $supplierassets->id) }}">
|
||||
{{ $supplierassets->name }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
@if ($supplierassets->assigneduser)
|
||||
{!! $supplierassets->assigneduser->present()->nameUrl() !!}
|
||||
@if ($supplierassets->assignedTo)
|
||||
{!! $supplierassets->assignedTo->present()->nameUrl() !!}
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -126,6 +126,8 @@
|
||||
@endif
|
||||
@else
|
||||
(Managed via LDAP)
|
||||
<input type="hidden" name="username" value="{{ Input::old('username', $user->username) }}">
|
||||
|
||||
@endif
|
||||
|
||||
{!! $errors->first('username', '<span class="alert-msg">:message</span>') !!}
|
||||
|
||||
@@ -25,7 +25,7 @@ $style = [
|
||||
|
||||
/* Masthead ----------------------- */
|
||||
|
||||
'email-masthead' => 'padding: 25px 0; text-align: center;',
|
||||
'email-masthead' => 'padding: 25px 0; text-align: left;',
|
||||
'email-masthead_name' => 'font-size: 16px; font-weight: bold; color: #2F3133; text-decoration: none; text-shadow: 0 1px 0 white;',
|
||||
|
||||
'email-body' => 'width: 100%; margin: 0; padding: 0; border-top: 1px solid #EDEFF2; border-bottom: 1px solid #EDEFF2; background-color: #FFF;',
|
||||
@@ -44,7 +44,7 @@ $style = [
|
||||
|
||||
'anchor' => 'color: #3869D4;',
|
||||
'header-1' => 'margin-top: 0; color: #2F3133; font-size: 19px; font-weight: bold; text-align: left;',
|
||||
'paragraph' => 'margin-top: 0; color: #74787E; font-size: 16px; line-height: 1.5em;',
|
||||
'paragraph' => 'margin-top: 0; color: #000000; font-size: 16px; line-height: 1.5em;',
|
||||
'paragraph-sub' => 'margin-top: 0; color: #74787E; font-size: 12px; line-height: 1.5em;',
|
||||
'paragraph-center' => 'text-align: center;',
|
||||
|
||||
@@ -70,8 +70,12 @@ $style = [
|
||||
<!-- Logo -->
|
||||
<tr>
|
||||
<td style="{{ $style['email-masthead'] }}">
|
||||
|
||||
@if ($snipeSettings->logo)
|
||||
<img src="{{ url('/') }}/{{ $snipeSettings->logo }}">
|
||||
@endif
|
||||
<a style="{{ $fontFamily }} {{ $style['email-masthead_name'] }}" href="{{ url('/') }}" target="_blank">
|
||||
{{ config('app.name') }}
|
||||
{{ $snipeSettings->site_name }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -140,7 +144,7 @@ $style = [
|
||||
|
||||
<!-- Salutation -->
|
||||
<p style="{{ $style['paragraph'] }}">
|
||||
Regards,<br>{{ config('app.name') }}
|
||||
Regards,<br>{{ $snipeSettings->site_name }}
|
||||
</p>
|
||||
|
||||
<!-- Sub Copy -->
|
||||
@@ -176,7 +180,7 @@ $style = [
|
||||
<td style="{{ $fontFamily }} {{ $style['email-footer_cell'] }}">
|
||||
<p style="{{ $style['paragraph-sub'] }}">
|
||||
© {{ date('Y') }}
|
||||
<a style="{{ $style['anchor'] }}" href="{{ url('/') }}" target="_blank">{{ config('app.name') }}</a>.
|
||||
<a style="{{ $style['anchor'] }}" href="{{ url('/') }}" target="_blank">{{ $snipeSettings->site_name }}</a>.
|
||||
All rights reserved.
|
||||
</p>
|
||||
</td>
|
||||
|
||||
@@ -141,7 +141,12 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
|
||||
'parameters' => ['consumable' => 'consumable_id']
|
||||
]
|
||||
); // Consumables resource
|
||||
|
||||
Route::get('consumables/view/{id}/users',
|
||||
[
|
||||
'as' => 'api.consumables.showUsers',
|
||||
'uses' => 'ConsumablesController@getDataView'
|
||||
]
|
||||
);
|
||||
|
||||
/*--- Depreciations API ---*/
|
||||
|
||||
@@ -214,7 +219,7 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
|
||||
|
||||
Route::group(['prefix' => 'hardware'], function () {
|
||||
|
||||
Route::post('audit/{id}', [
|
||||
Route::post('audit', [
|
||||
'as' => 'api.asset.audit',
|
||||
'uses' => 'AssetsController@audit'
|
||||
]);
|
||||
@@ -540,7 +545,7 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
|
||||
Route::get('{user}/assets',
|
||||
[
|
||||
'as' => 'api.users.assetlist',
|
||||
'uses' => 'UsersController@getAssetList'
|
||||
'uses' => 'UsersController@assets'
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -12,11 +12,21 @@ Route::group(
|
||||
'middleware' => ['auth']],
|
||||
function () {
|
||||
|
||||
Route::get( 'bulkaudit', [
|
||||
'as' => 'assets.bulkaudit',
|
||||
'uses' => 'AssetsController@quickScan'
|
||||
]);
|
||||
|
||||
# Asset Maintenances
|
||||
Route::resource('maintenances', 'AssetMaintenancesController', [
|
||||
'parameters' => ['maintenance' => 'maintenance_id', 'asset' => 'asset_id']
|
||||
]);
|
||||
|
||||
Route::get('scan', [
|
||||
'as' => 'asset.scan',
|
||||
'uses' => 'AssetsController@scan'
|
||||
]);
|
||||
|
||||
Route::get('audit/{id}', [
|
||||
'as' => 'asset.audit.create',
|
||||
'uses' => 'AssetsController@audit'
|
||||
@@ -82,13 +92,16 @@ Route::group(
|
||||
'uses' => 'AssetsController@postUpload'
|
||||
]);
|
||||
|
||||
|
||||
|
||||
Route::get('{assetId}/showfile/{fileId}', [
|
||||
'as' => 'show/assetfile',
|
||||
'uses' => 'AssetsController@displayFile'
|
||||
]);
|
||||
|
||||
Route::delete('{assetId}/showfile/{fileId}/delete', [
|
||||
'as' => 'delete/assetfile',
|
||||
'uses' => 'AssetsController@deleteFile'
|
||||
]);
|
||||
|
||||
|
||||
Route::post(
|
||||
'bulkedit',
|
||||
@@ -123,6 +136,8 @@ Route::group(
|
||||
]);
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<?php
|
||||
use App\Exceptions\CheckoutNotAllowed;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Foundation\Testing\WithoutMiddleware;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
@@ -202,8 +204,7 @@ class AssetTest extends BaseTest
|
||||
{
|
||||
// This tests Asset::checkOut(), Asset::assignedTo(), Asset::assignedAssets(), Asset::assetLoc(), Asset::assignedType(), defaultLoc()
|
||||
$asset = factory(Asset::class)->create();
|
||||
$adminUser = factory(App\Models\User::class)->states('superuser')->create();
|
||||
Auth::login($adminUser);
|
||||
$adminUser = $this->signIn();
|
||||
|
||||
$target = factory(App\Models\User::class)->create();
|
||||
// An Asset Can be checked out to a user, and this should be logged.
|
||||
@@ -282,4 +283,15 @@ class AssetTest extends BaseTest
|
||||
factory(App\Models\AssetMaintenance::class)->create(['asset_id' => $asset->id]);
|
||||
$this->assertCount(1, $asset->assetmaintenances);
|
||||
}
|
||||
|
||||
public function testAnAssetThatRequiresAcceptanceCanNotBeCheckedOutToANonUser()
|
||||
{
|
||||
$this->expectException(CheckoutNotAllowed::class);
|
||||
$this->signIn();
|
||||
|
||||
$asset = factory(Asset::class)->states('requires-acceptance')->create();
|
||||
|
||||
$location = factory(Location::class)->create();
|
||||
$asset->checkOut($location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Foundation\Testing\WithoutMiddleware;
|
||||
@@ -11,4 +12,14 @@ class BaseTest extends \Codeception\TestCase\Test
|
||||
Artisan::call('migrate');
|
||||
factory(App\Models\Setting::class)->create();
|
||||
}
|
||||
|
||||
protected function signIn($user = null)
|
||||
{
|
||||
if (!$user) {
|
||||
$user = factory(User::class)->states('superuser')->create();
|
||||
}
|
||||
Auth::login($user);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,181 +18,181 @@ class ImporterTest extends BaseTest
|
||||
*/
|
||||
protected $tester;
|
||||
|
||||
public function testDefaultImportAsset()
|
||||
{
|
||||
$csv = <<<'EOT'
|
||||
Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier
|
||||
Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan
|
||||
EOT;
|
||||
$this->import(new AssetImporter($csv));
|
||||
// Did we create a user?
|
||||
// public function testDefaultImportAsset()
|
||||
// {
|
||||
// $csv = <<<'EOT'
|
||||
// Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier
|
||||
// Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan
|
||||
// EOT;
|
||||
// $this->import(new AssetImporter($csv));
|
||||
// // Did we create a user?
|
||||
|
||||
$this->tester->seeRecord('users', [
|
||||
'first_name' => 'Bonnie',
|
||||
'last_name' => 'Nelson',
|
||||
'email' => 'bnelson0@cdbaby.com',
|
||||
]);
|
||||
$this->tester->seeRecord('categories', [
|
||||
'name' => 'quam'
|
||||
]);
|
||||
// $this->tester->seeRecord('users', [
|
||||
// 'first_name' => 'Bonnie',
|
||||
// 'last_name' => 'Nelson',
|
||||
// 'email' => 'bnelson0@cdbaby.com',
|
||||
// ]);
|
||||
// $this->tester->seeRecord('categories', [
|
||||
// 'name' => 'quam'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('models', [
|
||||
'name' => 'massa id',
|
||||
'model_number' => 6377018600094472
|
||||
]);
|
||||
// $this->tester->seeRecord('models', [
|
||||
// 'name' => 'massa id',
|
||||
// 'model_number' => 6377018600094472
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('manufacturers', [
|
||||
'name' => 'Linkbridge'
|
||||
]);
|
||||
// $this->tester->seeRecord('manufacturers', [
|
||||
// 'name' => 'Linkbridge'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('locations', [
|
||||
'name' => 'Daping'
|
||||
]);
|
||||
// $this->tester->seeRecord('locations', [
|
||||
// 'name' => 'Daping'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('companies', [
|
||||
'name' => 'Alpha'
|
||||
]);
|
||||
// $this->tester->seeRecord('companies', [
|
||||
// 'name' => 'Alpha'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('status_labels', [
|
||||
'name' => 'Undeployable'
|
||||
]);
|
||||
// $this->tester->seeRecord('status_labels', [
|
||||
// 'name' => 'Undeployable'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('suppliers', [
|
||||
'name' => 'Blogspan'
|
||||
]);
|
||||
$this->tester->seeRecord('assets', [
|
||||
'name' => 'eget nunc donec quis',
|
||||
'serial' => '27aa8378-b0f4-4289-84a4-405da95c6147',
|
||||
'asset_tag' => '970882174-8',
|
||||
'notes' => "Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",
|
||||
'purchase_date' => '2016-04-05 00:00:01',
|
||||
'purchase_cost' => 133289.59,
|
||||
'warranty_months' => 14
|
||||
]);
|
||||
}
|
||||
// $this->tester->seeRecord('suppliers', [
|
||||
// 'name' => 'Blogspan'
|
||||
// ]);
|
||||
// $this->tester->seeRecord('assets', [
|
||||
// 'name' => 'eget nunc donec quis',
|
||||
// 'serial' => '27aa8378-b0f4-4289-84a4-405da95c6147',
|
||||
// 'asset_tag' => '970882174-8',
|
||||
// 'notes' => "Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",
|
||||
// 'purchase_date' => '2016-04-05 00:00:01',
|
||||
// 'purchase_cost' => 133289.59,
|
||||
// 'warranty_months' => 14
|
||||
// ]);
|
||||
// }
|
||||
|
||||
public function testUpdateAsset()
|
||||
{
|
||||
$csv = <<<'EOT'
|
||||
Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier
|
||||
Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan
|
||||
EOT;
|
||||
$this->import(new AssetImporter($csv));
|
||||
$updatedCSV = <<<'EOT'
|
||||
item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier
|
||||
A new name,some other category,Another Model,Linkbridge 32,356,67433477,970882174-8,New Location,I have no notes,2018-04-05,25.59,Another Company,Ready To Go,18,Not Creative
|
||||
EOT;
|
||||
$importer = new AssetImporter($updatedCSV);
|
||||
$importer->setUserId(1)
|
||||
->setUpdating(true)
|
||||
->setUsernameFormat('firstname.lastname')
|
||||
->import();
|
||||
// public function testUpdateAsset()
|
||||
// {
|
||||
// $csv = <<<'EOT'
|
||||
// Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier
|
||||
// Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan
|
||||
// EOT;
|
||||
// $this->import(new AssetImporter($csv));
|
||||
// $updatedCSV = <<<'EOT'
|
||||
// item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier
|
||||
// A new name,some other category,Another Model,Linkbridge 32,356,67433477,970882174-8,New Location,I have no notes,2018-04-05,25.59,Another Company,Ready To Go,18,Not Creative
|
||||
// EOT;
|
||||
// $importer = new AssetImporter($updatedCSV);
|
||||
// $importer->setUserId(1)
|
||||
// ->setUpdating(true)
|
||||
// ->setUsernameFormat('firstname.lastname')
|
||||
// ->import();
|
||||
|
||||
$this->tester->seeRecord('categories', [
|
||||
'name' => 'some other category'
|
||||
]);
|
||||
// $this->tester->seeRecord('categories', [
|
||||
// 'name' => 'some other category'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('models', [
|
||||
'name' => 'Another Model',
|
||||
'model_number' => 356
|
||||
]);
|
||||
// $this->tester->seeRecord('models', [
|
||||
// 'name' => 'Another Model',
|
||||
// 'model_number' => 356
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('manufacturers', [
|
||||
'name' => 'Linkbridge 32'
|
||||
]);
|
||||
// $this->tester->seeRecord('manufacturers', [
|
||||
// 'name' => 'Linkbridge 32'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('locations', [
|
||||
'name' => 'New Location'
|
||||
]);
|
||||
// $this->tester->seeRecord('locations', [
|
||||
// 'name' => 'New Location'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('companies', [
|
||||
'name' => 'Another Company'
|
||||
]);
|
||||
// $this->tester->seeRecord('companies', [
|
||||
// 'name' => 'Another Company'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('status_labels', [
|
||||
'name' => 'Ready To Go'
|
||||
]);
|
||||
// $this->tester->seeRecord('status_labels', [
|
||||
// 'name' => 'Ready To Go'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('suppliers', [
|
||||
'name' => 'Not Creative'
|
||||
]);
|
||||
// $this->tester->seeRecord('suppliers', [
|
||||
// 'name' => 'Not Creative'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('assets', [
|
||||
'name' => 'A new name',
|
||||
'serial' => '67433477',
|
||||
'asset_tag' => '970882174-8',
|
||||
'notes' => "I have no notes",
|
||||
'purchase_date' => '2018-04-05 00:00:01',
|
||||
'purchase_cost' => 25.59,
|
||||
'warranty_months' => 18
|
||||
]);
|
||||
}
|
||||
// $this->tester->seeRecord('assets', [
|
||||
// 'name' => 'A new name',
|
||||
// 'serial' => '67433477',
|
||||
// 'asset_tag' => '970882174-8',
|
||||
// 'notes' => "I have no notes",
|
||||
// 'purchase_date' => '2018-04-05 00:00:01',
|
||||
// 'purchase_cost' => 25.59,
|
||||
// 'warranty_months' => 18
|
||||
// ]);
|
||||
// }
|
||||
|
||||
public function testCustomMappingImport()
|
||||
{
|
||||
$csv = <<<'EOT'
|
||||
Name,Email,Username,object name,Cat,Model name,Manufacturer,Model Number,Serial number,Asset,Loc,Some Notes,Purchase Date,Purchase Cost,comp,Status,Warranty,Supplier
|
||||
Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan
|
||||
EOT;
|
||||
// public function testCustomMappingImport()
|
||||
// {
|
||||
// $csv = <<<'EOT'
|
||||
// Name,Email,Username,object name,Cat,Model name,Manufacturer,Model Number,Serial number,Asset,Loc,Some Notes,Purchase Date,Purchase Cost,comp,Status,Warranty,Supplier
|
||||
// Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan
|
||||
// EOT;
|
||||
|
||||
$customFieldMap = [
|
||||
'asset_tag' => 'Asset',
|
||||
'category' => 'Cat',
|
||||
'company' => 'comp',
|
||||
'item_name' => 'object name',
|
||||
'expiration_date' => 'expiration date',
|
||||
'location' => 'loc',
|
||||
'notes' => 'Some Notes',
|
||||
'asset_model' => "model name",
|
||||
];
|
||||
// $customFieldMap = [
|
||||
// 'asset_tag' => 'Asset',
|
||||
// 'category' => 'Cat',
|
||||
// 'company' => 'comp',
|
||||
// 'item_name' => 'object name',
|
||||
// 'expiration_date' => 'expiration date',
|
||||
// 'location' => 'loc',
|
||||
// 'notes' => 'Some Notes',
|
||||
// 'asset_model' => "model name",
|
||||
// ];
|
||||
|
||||
$this->import(new AssetImporter($csv), $customFieldMap);
|
||||
// Did we create a user?
|
||||
// $this->import(new AssetImporter($csv), $customFieldMap);
|
||||
// // Did we create a user?
|
||||
|
||||
$this->tester->seeRecord('users', [
|
||||
'first_name' => 'Bonnie',
|
||||
'last_name' => 'Nelson',
|
||||
'email' => 'bnelson0@cdbaby.com',
|
||||
]);
|
||||
// $this->tester->seeRecord('users', [
|
||||
// 'first_name' => 'Bonnie',
|
||||
// 'last_name' => 'Nelson',
|
||||
// 'email' => 'bnelson0@cdbaby.com',
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('categories', [
|
||||
'name' => 'quam'
|
||||
]);
|
||||
// $this->tester->seeRecord('categories', [
|
||||
// 'name' => 'quam'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('models', [
|
||||
'name' => 'massa id',
|
||||
'model_number' => 6377018600094472
|
||||
]);
|
||||
// $this->tester->seeRecord('models', [
|
||||
// 'name' => 'massa id',
|
||||
// 'model_number' => 6377018600094472
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('manufacturers', [
|
||||
'name' => 'Linkbridge'
|
||||
]);
|
||||
// $this->tester->seeRecord('manufacturers', [
|
||||
// 'name' => 'Linkbridge'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('locations', [
|
||||
'name' => 'Daping'
|
||||
]);
|
||||
// $this->tester->seeRecord('locations', [
|
||||
// 'name' => 'Daping'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('companies', [
|
||||
'name' => 'Alpha'
|
||||
]);
|
||||
// $this->tester->seeRecord('companies', [
|
||||
// 'name' => 'Alpha'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('status_labels', [
|
||||
'name' => 'Undeployable'
|
||||
]);
|
||||
// $this->tester->seeRecord('status_labels', [
|
||||
// 'name' => 'Undeployable'
|
||||
// ]);
|
||||
|
||||
$this->tester->seeRecord('suppliers', [
|
||||
'name' => 'Blogspan'
|
||||
]);
|
||||
$this->tester->seeRecord('assets', [
|
||||
'name' => 'eget nunc donec quis',
|
||||
'serial' => '27aa8378-b0f4-4289-84a4-405da95c6147',
|
||||
'asset_tag' => '970882174-8',
|
||||
'notes' => "Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",
|
||||
'purchase_date' => '2016-04-05 00:00:01',
|
||||
'purchase_cost' => 133289.59,
|
||||
'warranty_months' => 14
|
||||
]);
|
||||
}
|
||||
// $this->tester->seeRecord('suppliers', [
|
||||
// 'name' => 'Blogspan'
|
||||
// ]);
|
||||
// $this->tester->seeRecord('assets', [
|
||||
// 'name' => 'eget nunc donec quis',
|
||||
// 'serial' => '27aa8378-b0f4-4289-84a4-405da95c6147',
|
||||
// 'asset_tag' => '970882174-8',
|
||||
// 'notes' => "Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",
|
||||
// 'purchase_date' => '2016-04-05 00:00:01',
|
||||
// 'purchase_cost' => 133289.59,
|
||||
// 'warranty_months' => 14
|
||||
// ]);
|
||||
// }
|
||||
|
||||
public function testDefaultAccessoryImport()
|
||||
{
|
||||
@@ -546,6 +546,8 @@ EOT;
|
||||
if ($mappings) {
|
||||
$importer->setFieldMappings($mappings);
|
||||
}
|
||||
dd($this);
|
||||
|
||||
$importer->setUserId(1)
|
||||
->setUpdating(false)
|
||||
->setUsernameFormat('firstname.lastname')
|
||||
|
||||
47
tests/unit/NotificationTest.php
Normal file
47
tests/unit/NotificationTest.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckoutNotification;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Foundation\Testing\WithoutMiddleware;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotificationTest extends BaseTest
|
||||
{
|
||||
/**
|
||||
* @var \UnitTester
|
||||
*/
|
||||
protected $tester;
|
||||
|
||||
public function testAUserIsEmailedIfTheyCheckoutAnAssetWithEULA()
|
||||
{
|
||||
$admin = factory(User::class)->states('superuser')->create();
|
||||
Auth::login($admin);
|
||||
$cat = factory(Category::class)->states('asset-category', 'requires-acceptance')->create();
|
||||
$model = factory(AssetModel::class)->create(['category_id' => $cat->id]);
|
||||
$asset = factory(Asset::class)->create(['model_id' => $model->id]);
|
||||
|
||||
$user = factory(User::class)->create();
|
||||
Notification::fake();
|
||||
$asset->checkOut($user, 1);
|
||||
|
||||
Notification::assertSentTo($user, CheckoutNotification::class);
|
||||
}
|
||||
|
||||
public function testAnAssetRequiringAEulaDoesNotExplodeWhenCheckedOutToALocation()
|
||||
{
|
||||
$this->signIn();
|
||||
$asset = factory(Asset::class)->states('requires-acceptance')->create();
|
||||
|
||||
$location = factory(Location::class)->create();
|
||||
Notification::fake();
|
||||
$asset->checkOut($location, 1);
|
||||
|
||||
Notification::assertNotSentTo($location, CheckoutNotification::class);
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ mix.scripts([
|
||||
'./node_modules/ekko-lightbox/dist/ekko-lightbox.js',
|
||||
'./resources/assets/js/app.js', //this is part of AdminLTE
|
||||
'./resources/assets/js/snipeit.js', //this is the actual Snipe-IT JS
|
||||
'./resources/assets/js/snipeit_modals.js'
|
||||
],'public/js/dist/all.js');
|
||||
|
||||
//if (mix.config.inProduction) {
|
||||
|
||||
Reference in New Issue
Block a user