mirror of
https://github.com/snipe/snipe-it.git
synced 2024-11-10 07:34:06 -08:00
Merge remote-tracking branch 'snipe-it-upstream/develop' into develop
This commit is contained in:
commit
b64924440f
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -52,3 +52,7 @@ tests/_support/_generated/*
|
|||
*.cache
|
||||
|
||||
.vagrant
|
||||
|
||||
\.php_cs\.dist
|
||||
|
||||
phpmd\.xml
|
||||
|
|
39
.php_cs.dist
Normal file
39
.php_cs.dist
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
ini_set('memory_limit', '1024M');
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->notPath('bootstrap/cache')
|
||||
->notPath('storage')
|
||||
->notPath('vendor')
|
||||
->notPath('node_modules')
|
||||
->in(__DIR__)
|
||||
->name('*.php')
|
||||
->notName('*.blade.php')
|
||||
->ignoreDotFiles(true)
|
||||
->ignoreVCS(true)
|
||||
;
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setRules(array(
|
||||
'@Symfony' => true,
|
||||
'class_definition' => [
|
||||
'multiLineExtendsEachSingleLine' => true,
|
||||
],
|
||||
'ordered_class_elements' => [
|
||||
'use_trait', 'constant_public', 'constant_protected', 'constant_private',
|
||||
'property_public', 'property_protected', 'property_private', 'construct',
|
||||
'destruct', 'magic', 'phpunit', 'method_public', 'method_protected',
|
||||
'method_private'
|
||||
],
|
||||
'function_declaration' => ['closure_function_spacing' => 'none'],
|
||||
'binary_operator_spaces' => ['default' => 'align_single_space_minimal'],
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'blank_line_after_namespace' => true,
|
||||
'linebreak_after_opening_tag' => true,
|
||||
'not_operator_with_successor_space' => true,
|
||||
'ordered_imports' => true,
|
||||
'phpdoc_order' => true,
|
||||
))
|
||||
->setFinder($finder);
|
|
@ -2,17 +2,15 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Notifications\ExpectedCheckinNotification;
|
||||
use App\Notifications\ExpectedCheckinAdminNotification;
|
||||
use App\Notifications\ExpectedCheckinNotification;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class SendExpectedCheckinAlerts extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
|
@ -29,8 +27,6 @@ class SendExpectedCheckinAlerts extends Command
|
|||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -44,30 +40,25 @@ class SendExpectedCheckinAlerts extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$settings = Setting::getSettings();
|
||||
$settings = Setting::getSettings();
|
||||
$whenNotify = Carbon::now()->addDays(7);
|
||||
$assets = Asset::with('assignedTo')->whereNotNull('assigned_to')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get();
|
||||
$assets = Asset::with('assignedTo')->whereNotNull('assigned_to')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get();
|
||||
|
||||
$this->info($whenNotify.' is deadline');
|
||||
$this->info($assets->count().' assets');
|
||||
$this->info($whenNotify . ' is deadline');
|
||||
$this->info($assets->count() . ' assets');
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
if ($asset->assigned && $asset->checkedOutToUser()) {
|
||||
if ($asset->assigned && $asset->checkedOutToUser()) {
|
||||
$asset->assigned->notify((new ExpectedCheckinNotification($asset)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Send a rollup to the admin, if settings dictate
|
||||
$recipient = new \App\Models\Recipients\AlertRecipient();
|
||||
|
||||
if (($assets) && ($assets->count() > 0) && ($settings->alert_email!='')) {
|
||||
$recipient->notify(new ExpectedCheckinAdminNotification($assets));
|
||||
if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) {
|
||||
// Send a rollup to the admin, if settings dictate
|
||||
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
|
||||
return new AlertRecipient($item);
|
||||
});
|
||||
Notification::send($recipients, new ExpectedCheckinAdminNotification($assets));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,14 @@ namespace App\Console\Commands;
|
|||
|
||||
use App\Models\Asset;
|
||||
use App\Models\License;
|
||||
use App\Models\Recipients\AlertRecipient;
|
||||
use App\Models\Setting;
|
||||
use DB;
|
||||
use App\Notifications\ExpiringLicenseNotification;
|
||||
use App\Notifications\ExpiringAssetsNotification;
|
||||
|
||||
use App\Notifications\ExpiringLicenseNotification;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class SendExpirationAlerts extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
|
@ -30,8 +28,6 @@ class SendExpirationAlerts extends Command
|
|||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -45,46 +41,35 @@ class SendExpirationAlerts extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
$settings = Setting::getSettings();
|
||||
$threshold = $settings->alert_interval;
|
||||
|
||||
if (($settings->alert_email != '') && ($settings->alerts_enabled == 1)) {
|
||||
|
||||
// Expiring Assets
|
||||
$assets = Asset::getExpiringWarrantee(Setting::getSettings()->alert_interval);
|
||||
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count'=>$assets->count(), 'threshold' => $threshold]));
|
||||
|
||||
// Expiring licenses
|
||||
$licenses = License::getExpiringLicenses($threshold);
|
||||
|
||||
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count'=>$licenses->count(), 'threshold' => $threshold]));
|
||||
|
||||
$recipient = new \App\Models\Recipients\AlertRecipient();
|
||||
|
||||
if ((Setting::getSettings()->alert_email!='') && ($settings->alerts_enabled==1)) {
|
||||
// Send a rollup to the admin, if settings dictate
|
||||
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
|
||||
return new AlertRecipient($item);
|
||||
});
|
||||
|
||||
// Expiring Assets
|
||||
$assets = Asset::getExpiringWarrantee(Setting::getSettings()->alert_interval);
|
||||
if ($assets->count() > 0) {
|
||||
// Send a rollup to the admin, if settings dictate
|
||||
$recipient->notify(new ExpiringAssetsNotification($assets, $threshold));
|
||||
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $threshold]));
|
||||
Notification::send($recipients, new ExpiringAssetsNotification($assets, $threshold));
|
||||
}
|
||||
|
||||
// Expiring licenses
|
||||
$licenses = License::getExpiringLicenses($threshold);
|
||||
if ($licenses->count() > 0) {
|
||||
$recipient->notify(new ExpiringLicenseNotification($licenses, $threshold));
|
||||
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $threshold]));
|
||||
Notification::send($recipients, new ExpiringLicenseNotification($licenses, $threshold));
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
if ($settings->alert_email=='') {
|
||||
if ($settings->alert_email == '') {
|
||||
$this->error('Could not send email. No alert email configured in settings');
|
||||
} elseif ($settings->alerts_enabled!=1) {
|
||||
} elseif (1 != $settings->alerts_enabled) {
|
||||
$this->info('Alerts are disabled in the settings. No mail will be sent');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Setting;
|
||||
use DB;
|
||||
use Mail;
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Recipients\AlertRecipient;
|
||||
use App\Models\Setting;
|
||||
use App\Notifications\InventoryAlert;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class SendInventoryAlerts extends Command
|
||||
{
|
||||
|
@ -28,8 +27,6 @@ class SendInventoryAlerts extends Command
|
|||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -45,28 +42,24 @@ class SendInventoryAlerts extends Command
|
|||
{
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
if (($settings->alert_email!='') && ($settings->alerts_enabled==1)) {
|
||||
|
||||
if (($settings->alert_email != '') && ($settings->alerts_enabled == 1)) {
|
||||
$items = Helper::checkLowInventory();
|
||||
|
||||
// Send a rollup to the admin, if settings dictate
|
||||
$recipient = new \App\Models\Recipients\AlertRecipient();
|
||||
if (($items) && (count($items) > 0)) {
|
||||
$this->info(trans_choice('mail.low_inventory_alert', count($items)));
|
||||
// Send a rollup to the admin, if settings dictate
|
||||
$recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) {
|
||||
return new AlertRecipient($item);
|
||||
});
|
||||
|
||||
if (($items) && (count($items) > 0) && ($settings->alert_email!='')) {
|
||||
|
||||
$this->info( trans_choice('mail.low_inventory_alert',count($items)) );
|
||||
|
||||
$recipient->notify(new InventoryAlert($items, $settings->alert_threshold));
|
||||
Notification::send($recipients, new InventoryAlert($items, $settings->alert_threshold));
|
||||
}
|
||||
|
||||
} else {
|
||||
if (Setting::getSettings()->alert_email=='') {
|
||||
if ($settings->alert_email == '') {
|
||||
$this->error('Could not send email. No alert email configured in settings');
|
||||
} elseif (Setting::getSettings()->alerts_enabled!=1) {
|
||||
} elseif (1 != $settings->alerts_enabled) {
|
||||
$this->info('Alerts are disabled in the settings. No mail will be sent');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
27
app/Events/CheckoutAccepted.php
Normal file
27
app/Events/CheckoutAccepted.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Contracts\Acceptable;
|
||||
use App\Models\User;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class CheckoutAccepted
|
||||
{
|
||||
use Dispatchable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(CheckoutAcceptance $acceptance)
|
||||
{
|
||||
$this->acceptance = $acceptance;
|
||||
}
|
||||
}
|
27
app/Events/CheckoutDeclined.php
Normal file
27
app/Events/CheckoutDeclined.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Contracts\Acceptable;
|
||||
use App\Models\User;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class CheckoutDeclined
|
||||
{
|
||||
use Dispatchable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(CheckoutAcceptance $acceptance)
|
||||
{
|
||||
$this->acceptance = $acceptance;
|
||||
}
|
||||
}
|
30
app/Events/CheckoutableCheckedIn.php
Normal file
30
app/Events/CheckoutableCheckedIn.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class CheckoutableCheckedIn
|
||||
{
|
||||
use Dispatchable, SerializesModels;
|
||||
|
||||
public $checkoutable;
|
||||
public $checkedOutTo;
|
||||
public $checkedInBy;
|
||||
public $note;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($checkoutable, $checkedOutTo, User $checkedInBy, $note)
|
||||
{
|
||||
$this->checkoutable = $checkoutable;
|
||||
$this->checkedOutTo = $checkedOutTo;
|
||||
$this->checkedInBy = $checkedInBy;
|
||||
$this->note = $note;
|
||||
}
|
||||
}
|
30
app/Events/CheckoutableCheckedOut.php
Normal file
30
app/Events/CheckoutableCheckedOut.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class CheckoutableCheckedOut
|
||||
{
|
||||
use Dispatchable, SerializesModels;
|
||||
|
||||
public $checkoutable;
|
||||
public $checkedOutTo;
|
||||
public $checkedOutBy;
|
||||
public $note;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note)
|
||||
{
|
||||
$this->checkoutable = $checkoutable;
|
||||
$this->checkedOutTo = $checkedOutTo;
|
||||
$this->checkedOutBy = $checkedOutBy;
|
||||
$this->note = $note;
|
||||
}
|
||||
}
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace App\Http\Controllers\Accessories;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
|
||||
|
@ -46,7 +48,7 @@ class AccessoryCheckinController extends Controller
|
|||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
* @internal param int $accessoryId
|
||||
*/
|
||||
public function store($accessoryUserId = null, $backto = null)
|
||||
public function store(Request $request, $accessoryUserId = null, $backto = null)
|
||||
{
|
||||
// Check if the accessory exists
|
||||
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
|
||||
|
@ -61,7 +63,8 @@ class AccessoryCheckinController extends Controller
|
|||
// Was the accessory updated?
|
||||
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {
|
||||
$return_to = e($accessory_user->assigned_to);
|
||||
$accessory->logCheckin(User::find($return_to), e(Input::get('note')));
|
||||
|
||||
event(new CheckoutableCheckedIn($accessory, User::find($return_to), Auth::user(), $request->input('note')));
|
||||
|
||||
return redirect()->route("accessories.show", $accessory->id)->with('success', trans('admin/accessories/message.checkin.success'));
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Accessories;
|
||||
|
||||
use App\Events\CheckoutableCheckedOut;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\User;
|
||||
|
@ -77,10 +78,10 @@ class AccessoryCheckoutController extends Controller
|
|||
'assigned_to' => $request->get('assigned_to')
|
||||
]);
|
||||
|
||||
$accessory->logCheckout(e(Input::get('note')), $user);
|
||||
|
||||
DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first();
|
||||
|
||||
event(new CheckoutableCheckedOut($accessory, $user, Auth::user(), $request->input('note')));
|
||||
|
||||
// Redirect to the new accessory page
|
||||
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.checkout.success'));
|
||||
}
|
||||
|
|
125
app/Http/Controllers/Account/AcceptanceController.php
Normal file
125
app/Http/Controllers/Account/AcceptanceController.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
namespace App\Http\Controllers\Account;
|
||||
|
||||
use App\Events\CheckoutAccepted;
|
||||
use App\Events\CheckoutDeclined;
|
||||
use App\Events\ItemAccepted;
|
||||
use App\Events\ItemDeclined;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Company;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\Contracts\Acceptable;
|
||||
use App\Models\License;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class AcceptanceController extends Controller {
|
||||
|
||||
/**
|
||||
* Show a listing of pending checkout acceptances for the current user
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function index() {
|
||||
$acceptances = CheckoutAcceptance::forUser(Auth::user())->pending()->get();
|
||||
|
||||
return view('account/accept.index', compact('acceptances'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a form to either accept or decline the checkout acceptance
|
||||
*
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function create($id) {
|
||||
|
||||
$acceptance = CheckoutAcceptance::find($id);
|
||||
|
||||
if (is_null($acceptance)) {
|
||||
return redirect()->reoute('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
|
||||
if (! $acceptance->isPending()) {
|
||||
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||
}
|
||||
|
||||
if (! $acceptance->isCheckedOutTo(Auth::user())) {
|
||||
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||
}
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($acceptance->checkoutable)) {
|
||||
return redirect()->route('account.accept')->with('error', trans('general.insufficient_permissions'));
|
||||
}
|
||||
|
||||
return view('account/accept.create', compact('acceptance'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the accept/decline of the checkout acceptance
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Redirect
|
||||
*/
|
||||
public function store(Request $request, $id) {
|
||||
|
||||
$acceptance = CheckoutAcceptance::find($id);
|
||||
|
||||
if (is_null($acceptance)) {
|
||||
return redirect()->reoute('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
|
||||
if (! $acceptance->isPending()) {
|
||||
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||
}
|
||||
|
||||
if (! $acceptance->isCheckedOutTo(Auth::user())) {
|
||||
return redirect()->route('account.accept')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||
}
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($acceptance->checkoutable)) {
|
||||
return redirect()->route('account.accept')->with('error', trans('general.insufficient_permissions'));
|
||||
}
|
||||
|
||||
if (!$request->filled('asset_acceptance')) {
|
||||
return redirect()->back()->with('error', trans('admin/users/message.error.accept_or_decline'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the signature and save it
|
||||
*/
|
||||
if ($request->filled('signature_output')) {
|
||||
$path = config('app.private_uploads').'/signatures';
|
||||
$sig_filename = "siglog-" .Str::uuid() . '-'.date('Y-m-d-his').".png";
|
||||
$data_uri = e($request->input('signature_output'));
|
||||
$encoded_image = explode(",", $data_uri);
|
||||
$decoded_image = base64_decode($encoded_image[1]);
|
||||
file_put_contents($path."/".$sig_filename, $decoded_image);
|
||||
}
|
||||
|
||||
|
||||
if ($request->input('asset_acceptance') == 'accepted') {
|
||||
|
||||
$acceptance->accept($sig_filename);
|
||||
|
||||
event(new CheckoutAccepted($acceptance));
|
||||
|
||||
$return_msg = trans('admin/users/message.accepted');
|
||||
|
||||
} else {
|
||||
|
||||
$acceptance->decline($sig_filename);
|
||||
|
||||
event(new CheckoutDeclined($acceptance));
|
||||
|
||||
$return_msg = trans('admin/users/message.declined');
|
||||
|
||||
}
|
||||
|
||||
return redirect()->to('account/accept')->with('success', $return_msg);
|
||||
}
|
||||
}
|
|
@ -143,13 +143,16 @@ class AccessoriesController extends Controller
|
|||
|
||||
$accessory->lastCheckoutArray = $accessory->lastCheckout->toArray();
|
||||
$accessory_users = $accessory->users;
|
||||
|
||||
if($request->filled('search')){
|
||||
$accessory_users = $accessory_users->where('first_name', $request->input('search'))->concat($accessory_users->where('last_name', $request->input('search')));
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$accessory_users = $accessory->users()
|
||||
->where('first_name', 'like', '%'.$request->input('search').'%')
|
||||
->orWhere('last_name', 'like', '%'.$request->input('search').'%')
|
||||
->get();
|
||||
}
|
||||
|
||||
$total = $accessory_users->count();
|
||||
|
||||
|
||||
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_users, $total);
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ class LicensesController extends Controller
|
|||
public function show($id)
|
||||
{
|
||||
$this->authorize('view', License::class);
|
||||
$license = License::findOrFail($id);
|
||||
$license = License::withCount('freeSeats')->findOrFail($id);
|
||||
$license = $license->load('assignedusers', 'licenseSeats.user', 'licenseSeats.asset');
|
||||
return (new LicensesTransformer)->transformLicense($license);
|
||||
}
|
||||
|
|
|
@ -106,7 +106,26 @@ class LocationsController extends Controller
|
|||
public function show($id)
|
||||
{
|
||||
$this->authorize('view', Location::class);
|
||||
$location = Location::findOrFail($id);
|
||||
$location = Location::with('parent', 'manager', 'childLocations')
|
||||
->select([
|
||||
'locations.id',
|
||||
'locations.name',
|
||||
'locations.address',
|
||||
'locations.address2',
|
||||
'locations.city',
|
||||
'locations.state',
|
||||
'locations.zip',
|
||||
'locations.country',
|
||||
'locations.parent_id',
|
||||
'locations.manager_id',
|
||||
'locations.created_at',
|
||||
'locations.updated_at',
|
||||
'locations.image',
|
||||
'locations.currency'
|
||||
])
|
||||
->withCount('assignedAssets')
|
||||
->withCount('assets')
|
||||
->withCount('users')->findOrFail($id);
|
||||
return (new LocationsTransformer)->transformLocation($location);
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ class ManufacturersController extends Controller
|
|||
public function show($id)
|
||||
{
|
||||
$this->authorize('view', Manufacturer::class);
|
||||
$manufacturer = Manufacturer::findOrFail($id);
|
||||
$manufacturer = Manufacturer::withCount('assets as assets_count', 'licenses as licenses_count', 'consumables as consumables_count', 'accessories as accessories_count', 'models as models_count' )->findOrFail($id);
|
||||
return (new ManufacturersTransformer)->transformManufacturer($manufacturer);
|
||||
}
|
||||
|
||||
|
@ -120,11 +120,21 @@ class ManufacturersController extends Controller
|
|||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
|
||||
$this->authorize('delete', Manufacturer::class);
|
||||
$manufacturer = Manufacturer::findOrFail($id);
|
||||
$manufacturer = Manufacturer::withCount('assets as assets_count', 'licenses as licenses_count', 'consumables as consumables_count', 'accessories as accessories_count', 'models as models_count' )->findOrFail($id);
|
||||
$this->authorize('delete', $manufacturer);
|
||||
$manufacturer->delete();
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success')));
|
||||
|
||||
if (($manufacturer->assets_count == 0) && ($manufacturer->licenses_count==0) && ($manufacturer->consumables_count==0) && ($manufacturer->accessories_count==0) && ($manufacturer->models_count==0) && ($manufacturer->deleted_at=='')) {
|
||||
$manufacturer->delete();
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success')));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/manufacturers/message.delete.error')));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -238,9 +238,6 @@ class StatuslabelsController extends Controller
|
|||
*/
|
||||
public function checkIfDeployable($id) {
|
||||
$statuslabel = Statuslabel::findOrFail($id);
|
||||
|
||||
$this->authorize('view', $statuslabel);
|
||||
|
||||
if ($statuslabel->getStatuslabelType()=='deployable') {
|
||||
return '1';
|
||||
}
|
||||
|
|
|
@ -203,6 +203,8 @@ class UsersController extends Controller
|
|||
if ($user->save()) {
|
||||
if ($request->filled('groups')) {
|
||||
$user->groups()->sync($request->input('groups'));
|
||||
} else {
|
||||
$user->groups()->sync(array());
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.create')));
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace App\Http\Controllers\Assets;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AssetCheckinRequest;
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\View;
|
||||
|
||||
|
@ -82,8 +84,8 @@ class AssetCheckinController extends Controller
|
|||
|
||||
// Was the asset updated?
|
||||
if ($asset->save()) {
|
||||
$asset->logCheckin($target, e(request('note')));
|
||||
|
||||
|
||||
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note')));
|
||||
|
||||
if ($backto=='user') {
|
||||
return redirect()->route("users.show", $user->id)->with('success', trans('admin/hardware/message.checkin.success'));
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
namespace App\Http\Controllers\Components;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Events\ComponentCheckedIn;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Component;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
|
@ -86,22 +89,16 @@ class ComponentCheckinController extends Controller
|
|||
DB::table('components_assets')->where('id',
|
||||
$component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
|
||||
|
||||
$log = new Actionlog();
|
||||
$log->user_id = auth()->id();
|
||||
$log->action_type = 'checkin from';
|
||||
$log->target_type = Asset::class;
|
||||
$log->target_id = $component_assets->asset_id;
|
||||
$log->item_id = $component_assets->component_id;
|
||||
$log->item_type = Component::class;
|
||||
$log->note = $request->input('note');
|
||||
$log->save();
|
||||
|
||||
// If the checked-in qty is exactly the same as the assigned_qty,
|
||||
// we can simply delete the associated components_assets record
|
||||
if ($qty_remaining_in_checkout == 0) {
|
||||
DB::table('components_assets')->where('id', '=', $component_asset_id)->delete();
|
||||
}
|
||||
|
||||
$asset = Asset::find($component_assets->asset_id);
|
||||
|
||||
event(new CheckoutableCheckedIn($component, $asset, Auth::user(), $request->input('note')));
|
||||
|
||||
return redirect()->route('components.index')->with('success',
|
||||
trans('admin/components/message.checkout.success'));
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Http\Controllers\Components;
|
||||
|
||||
use App\Events\CheckoutableCheckedOut;
|
||||
use App\Events\ComponentCheckedOut;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Component;
|
||||
|
@ -86,7 +88,8 @@ class ComponentCheckoutController extends Controller
|
|||
'asset_id' => $asset_id
|
||||
]);
|
||||
|
||||
$component->logCheckout(e(Input::get('note')), $asset);
|
||||
event(new CheckoutableCheckedOut($component, $asset, Auth::user(), $request->input('note')));
|
||||
|
||||
return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
namespace App\Http\Controllers\Consumables;
|
||||
|
||||
use App\Events\CheckoutableCheckedOut;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
|
||||
|
@ -41,7 +42,7 @@ class ConsumableCheckoutController extends Controller
|
|||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function store($consumableId)
|
||||
public function store(Request $request, $consumableId)
|
||||
{
|
||||
if (is_null($consumable = Consumable::find($consumableId))) {
|
||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found'));
|
||||
|
@ -67,7 +68,7 @@ class ConsumableCheckoutController extends Controller
|
|||
'assigned_to' => e(Input::get('assigned_to'))
|
||||
]);
|
||||
|
||||
$consumable->logCheckout(e(Input::get('note')), $user);
|
||||
event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note')));
|
||||
|
||||
// Redirect to the new consumable page
|
||||
return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.checkout.success'));
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
namespace App\Http\Controllers\Licenses;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Models\Asset;
|
||||
use App\Models\License;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
@ -49,7 +51,7 @@ class LicenseCheckinController extends Controller
|
|||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function store($seatId = null, $backTo = null)
|
||||
public function store(Request $request, $seatId = null, $backTo = null)
|
||||
{
|
||||
// Check if the asset exists
|
||||
if (is_null($licenseSeat = LicenseSeat::find($seatId))) {
|
||||
|
@ -88,7 +90,9 @@ class LicenseCheckinController extends Controller
|
|||
|
||||
// Was the asset updated?
|
||||
if ($licenseSeat->save()) {
|
||||
$licenseSeat->logCheckin($return_to, e(request('note')));
|
||||
|
||||
event(new CheckoutableCheckedIn($license, $return_to, Auth::user(), $request->input('note')));
|
||||
|
||||
if ($backTo=='user') {
|
||||
return redirect()->route("users.show", $return_to->id)->with('success', trans('admin/licenses/message.checkin.success'));
|
||||
}
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
|
||||
namespace App\Http\Controllers\Licenses;
|
||||
|
||||
use App\Events\CheckoutableCheckedOut;
|
||||
use App\Http\Requests\LicenseCheckoutRequest;
|
||||
use App\Models\Asset;
|
||||
use App\Models\License;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class LicenseCheckoutController extends Controller
|
||||
|
@ -103,7 +104,9 @@ class LicenseCheckoutController extends Controller
|
|||
$licenseSeat->assigned_to = $target->assigned_to;
|
||||
}
|
||||
if ($licenseSeat->save()) {
|
||||
$licenseSeat->logCheckout(request('note'), $target);
|
||||
|
||||
event(new CheckoutableCheckedOut($licenseSeat, $target, Auth::user(), request('note')));
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -118,7 +121,9 @@ class LicenseCheckoutController extends Controller
|
|||
$licenseSeat->assigned_to = request('assigned_to');
|
||||
|
||||
if ($licenseSeat->save()) {
|
||||
$licenseSeat->logCheckout(request('note'), $target);
|
||||
|
||||
event(new CheckoutableCheckedOut($licenseSeat, $target, Auth::user(), request('note')));
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -7,6 +7,7 @@ use App\Models\Actionlog;
|
|||
use App\Models\Asset;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Depreciation;
|
||||
use App\Models\License;
|
||||
use App\Models\Setting;
|
||||
|
@ -805,7 +806,20 @@ class ReportsController extends Controller
|
|||
public function getAssetAcceptanceReport()
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
$assetsForReport = Asset::notYetAccepted()->with('company')->get();
|
||||
|
||||
/**
|
||||
* Get all assets with pending checkout acceptances
|
||||
*/
|
||||
|
||||
$acceptances = CheckoutAcceptance::pending()->get();
|
||||
|
||||
$assetsForReport = $acceptances
|
||||
->filter(function($acceptance) {
|
||||
return $acceptance->checkoutable_type == 'App\Models\Asset';
|
||||
})
|
||||
->map(function($acceptance) {
|
||||
return $acceptance->checkoutable;
|
||||
});
|
||||
|
||||
return view('reports/unaccepted_assets', compact('assetsForReport'));
|
||||
}
|
||||
|
|
|
@ -199,124 +199,6 @@ class ViewAssetsController extends Controller
|
|||
// Get the acceptance screen
|
||||
public function getAcceptAsset($logID = null)
|
||||
{
|
||||
|
||||
$findlog = Actionlog::where('id', $logID)->first();
|
||||
|
||||
if (!$findlog) {
|
||||
return redirect()->to('account/view-assets')->with('error', 'No matching record.');
|
||||
}
|
||||
|
||||
if ($findlog->accepted_id!='') {
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
|
||||
// TODO - Fix this for non-assets
|
||||
if (($findlog->item_type==Asset::class) && ($user->id != $findlog->item->assigned_to)) {
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||
}
|
||||
|
||||
|
||||
$item = $findlog->item;
|
||||
|
||||
// Check if the asset exists
|
||||
if (is_null($item)) {
|
||||
// Redirect to the asset management page
|
||||
return redirect()->to('account')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
if (!Company::isCurrentUserHasAccess($item)) {
|
||||
return redirect()->route('requestable-assets')->with('error', trans('general.insufficient_permissions'));
|
||||
}
|
||||
return view('account/accept-asset', compact('item'))->with('findlog', $findlog)->with('item', $item);
|
||||
}
|
||||
|
||||
// Save the acceptance
|
||||
public function postAcceptAsset(Request $request, $logID = null)
|
||||
{
|
||||
|
||||
// Check if the asset exists
|
||||
if (is_null($findlog = Actionlog::where('id', $logID)->first())) {
|
||||
// Redirect to the asset management page
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
|
||||
|
||||
if ($findlog->accepted_id!='') {
|
||||
// Redirect to the asset management page
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.asset_already_accepted'));
|
||||
}
|
||||
|
||||
if (!Input::has('asset_acceptance')) {
|
||||
return redirect()->back()->with('error', trans('admin/users/message.error.accept_or_decline'));
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
if (($findlog->item_type==Asset::class) && ($user->id != $findlog->item->assigned_to)) {
|
||||
return redirect()->to('account/view-assets')->with('error', trans('admin/users/message.error.incorrect_user_accepted'));
|
||||
}
|
||||
|
||||
if ($request->filled('signature_output')) {
|
||||
$path = config('app.private_uploads').'/signatures';
|
||||
$sig_filename = "siglog-".$findlog->id.'-'.date('Y-m-d-his').".png";
|
||||
$data_uri = e($request->get('signature_output'));
|
||||
$encoded_image = explode(",", $data_uri);
|
||||
$decoded_image = base64_decode($encoded_image[1]);
|
||||
file_put_contents($path."/".$sig_filename, $decoded_image);
|
||||
}
|
||||
|
||||
|
||||
$logaction = new Actionlog();
|
||||
|
||||
if (Input::get('asset_acceptance')=='accepted') {
|
||||
$logaction_msg = 'accepted';
|
||||
$accepted="accepted";
|
||||
$return_msg = trans('admin/users/message.accepted');
|
||||
} else {
|
||||
$logaction_msg = 'declined';
|
||||
$accepted="rejected";
|
||||
$return_msg = trans('admin/users/message.declined');
|
||||
}
|
||||
$logaction->item_id = $findlog->item_id;
|
||||
$logaction->item_type = $findlog->item_type;
|
||||
|
||||
// Asset
|
||||
if (($findlog->item_id!='') && ($findlog->item_type==Asset::class)) {
|
||||
if (Input::get('asset_acceptance')!='accepted') {
|
||||
DB::table('assets')
|
||||
->where('id', $findlog->item_id)
|
||||
->update(array('assigned_to' => null));
|
||||
}
|
||||
}
|
||||
|
||||
$logaction->target_id = $findlog->target_id;
|
||||
$logaction->target_type = User::class;
|
||||
$logaction->note = e(Input::get('note'));
|
||||
$logaction->updated_at = date("Y-m-d H:i:s");
|
||||
|
||||
|
||||
if (isset($sig_filename)) {
|
||||
$logaction->accept_signature = $sig_filename;
|
||||
}
|
||||
$log = $logaction->logaction($logaction_msg);
|
||||
|
||||
$update_checkout = DB::table('action_logs')
|
||||
->where('id', $findlog->id)
|
||||
->update(array('accepted_id' => $logaction->id));
|
||||
|
||||
if (($findlog->item_id!='') && ($findlog->item_type==Asset::class)) {
|
||||
$affected_asset = $logaction->item;
|
||||
$affected_asset->accepted = $accepted;
|
||||
$affected_asset->save();
|
||||
}
|
||||
|
||||
if ($update_checkout) {
|
||||
return redirect()->to('account/view-assets')->with('success', $return_msg);
|
||||
|
||||
}
|
||||
return redirect()->to('account/view-assets')->with('error', 'Something went wrong ');
|
||||
|
||||
return redirect()->route('account.accept');
|
||||
}
|
||||
}
|
||||
|
|
184
app/Listeners/CheckoutableListener.php
Normal file
184
app/Listeners/CheckoutableListener.php
Normal file
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\Recipients\AdminRecipient;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckinAccessoryNotification;
|
||||
use App\Notifications\CheckinAssetNotification;
|
||||
use App\Notifications\CheckinLicenseNotification;
|
||||
use App\Notifications\CheckinLicenseSeatNotification;
|
||||
use App\Notifications\CheckoutAccessoryNotification;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
use App\Notifications\CheckoutConsumableNotification;
|
||||
use App\Notifications\CheckoutLicenseNotification;
|
||||
use App\Notifications\CheckoutLicenseSeatNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class CheckoutableListener
|
||||
{
|
||||
|
||||
/**
|
||||
* Notify the user about the checked out checkoutable
|
||||
*/
|
||||
public function onCheckedOut($event) {
|
||||
/**
|
||||
* When the item wasn't checked out to a user, we can't send notifications
|
||||
*/
|
||||
if(! $event->checkedOutTo instanceof User) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a checkout acceptance and attach it in the notification
|
||||
*/
|
||||
$acceptance = $this->getCheckoutAcceptance($event);
|
||||
|
||||
Notification::send(
|
||||
$this->getNotifiables($event),
|
||||
$this->getCheckoutNotification($event, $acceptance)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the user about the checked in checkoutable
|
||||
*/
|
||||
public function onCheckedIn($event) {
|
||||
/**
|
||||
* When the item wasn't checked out to a user, we can't send notifications
|
||||
*/
|
||||
if(!$event->checkedOutTo instanceof User) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the appropriate notification
|
||||
*/
|
||||
Notification::send(
|
||||
$this->getNotifiables($event),
|
||||
$this->getCheckinNotification($event)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a checkout acceptance
|
||||
* @param Event $event
|
||||
* @return mixed
|
||||
*/
|
||||
private function getCheckoutAcceptance($event) {
|
||||
if (!$event->checkoutable->requireAcceptance()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$acceptance = new CheckoutAcceptance;
|
||||
$acceptance->checkoutable()->associate($event->checkoutable);
|
||||
$acceptance->assignedTo()->associate($event->checkedOutTo);
|
||||
$acceptance->save();
|
||||
|
||||
return $acceptance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entities to be notified of the passed event
|
||||
*
|
||||
* @param Event $event
|
||||
* @return Collection
|
||||
*/
|
||||
private function getNotifiables($event) {
|
||||
$notifiables = collect();
|
||||
|
||||
/**
|
||||
* Notify the user who checked out the item
|
||||
*/
|
||||
$notifiables->push($event->checkedOutTo);
|
||||
|
||||
/**
|
||||
* Notify Admin users if the settings is activated
|
||||
*/
|
||||
if (Setting::getSettings()->admin_cc_email != '') {
|
||||
$notifiables->push(new AdminRecipient());
|
||||
}
|
||||
|
||||
return $notifiables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate notification for the event
|
||||
*
|
||||
* @param CheckoutableCheckedIn $event
|
||||
* @return Notification
|
||||
*/
|
||||
private function getCheckinNotification($event) {
|
||||
|
||||
$model = get_class($event->checkoutable);
|
||||
|
||||
$notificationClass = null;
|
||||
|
||||
switch (get_class($event->checkoutable)) {
|
||||
case Accessory::class:
|
||||
$notificationClass = CheckinAccessoryNotification::class;
|
||||
break;
|
||||
case Asset::class:
|
||||
$notificationClass = CheckinAssetNotification::class;
|
||||
break;
|
||||
case LicenseSeat::class:
|
||||
$notificationClass = CheckinLicenseSeatNotification::class;
|
||||
break;
|
||||
}
|
||||
|
||||
return new $notificationClass($event->checkoutable, $event->checkedOutTo, $event->checkedInBy, $event->note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate notification for the event
|
||||
*
|
||||
* @param CheckoutableCheckedIn $event
|
||||
* @param CheckoutAcceptance $acceptance
|
||||
* @return Notification
|
||||
*/
|
||||
private function getCheckoutNotification($event, $acceptance) {
|
||||
$notificationClass = null;
|
||||
|
||||
switch (get_class($event->checkoutable)) {
|
||||
case Accessory::class:
|
||||
$notificationClass = CheckoutAccessoryNotification::class;
|
||||
break;
|
||||
case Asset::class:
|
||||
$notificationClass = CheckoutAssetNotification::class;
|
||||
break;
|
||||
case Consumable::class:
|
||||
$notificationClass = CheckoutConsumableNotification::class;
|
||||
break;
|
||||
case LicenseSeat::class:
|
||||
$notificationClass = CheckoutLicenseSeatNotification::class;
|
||||
break;
|
||||
}
|
||||
|
||||
return new $notificationClass($event->checkoutable, $event->checkedOutTo, $event->checkedOutBy, $acceptance, $event->note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the listeners for the subscriber.
|
||||
*
|
||||
* @param Illuminate\Events\Dispatcher $events
|
||||
*/
|
||||
public function subscribe($events)
|
||||
{
|
||||
$events->listen(
|
||||
'App\Events\CheckoutableCheckedIn',
|
||||
'App\Listeners\CheckoutableListener@onCheckedIn'
|
||||
);
|
||||
|
||||
$events->listen(
|
||||
'App\Events\CheckoutableCheckedOut',
|
||||
'App\Listeners\CheckoutableListener@onCheckedOut'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
90
app/Listeners/LogListener.php
Normal file
90
app/Listeners/LogListener.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\AccessoryCheckedIn;
|
||||
use App\Events\AccessoryCheckedOut;
|
||||
use App\Events\AssetCheckedIn;
|
||||
use App\Events\AssetCheckedOut;
|
||||
use App\Events\CheckoutAccepted;
|
||||
use App\Events\CheckoutDeclined;
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Events\CheckoutableCheckedOut;
|
||||
use App\Events\ComponentCheckedIn;
|
||||
use App\Events\ComponentCheckedOut;
|
||||
use App\Events\ConsumableCheckedOut;
|
||||
use App\Events\ItemAccepted;
|
||||
use App\Events\ItemDeclined;
|
||||
use App\Events\LicenseCheckedIn;
|
||||
use App\Events\LicenseCheckedOut;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Component;
|
||||
use App\Models\LicenseSeat;
|
||||
|
||||
|
||||
class LogListener
|
||||
{
|
||||
|
||||
public function onCheckoutableCheckedIn(CheckoutableCheckedIn $event) {
|
||||
$event->checkoutable->logCheckin($event->checkedOutTo, $event->note);
|
||||
}
|
||||
|
||||
public function onCheckoutableCheckedOut(CheckoutableCheckedOut $event) {
|
||||
$event->checkoutable->logCheckout($event->note, $event->checkedOutTo);
|
||||
}
|
||||
|
||||
public function onCheckoutAccepted(CheckoutAccepted $event) {
|
||||
$logaction = new Actionlog();
|
||||
|
||||
$logaction->item()->associate($event->acceptance->checkoutable);
|
||||
$logaction->target()->associate($event->acceptance->assignedTo);
|
||||
$logaction->accept_signature = $event->acceptance->signature_filename;
|
||||
$logaction->action_type = 'accepted';
|
||||
|
||||
// TODO: log the actual license seat that was checked out
|
||||
if($event->acceptance->checkoutable instanceof LicenseSeat) {
|
||||
$logaction->item()->associate($event->acceptance->checkoutable->license);
|
||||
}
|
||||
|
||||
$logaction->save();
|
||||
}
|
||||
|
||||
public function onCheckoutDeclined(CheckoutDeclined $event) {
|
||||
$logaction = new Actionlog();
|
||||
$logaction->item()->associate($event->acceptance->checkoutable);
|
||||
$logaction->target()->associate($event->acceptance->assignedTo);
|
||||
$logaction->accept_signature = $event->acceptance->signature_filename;
|
||||
$logaction->action_type = 'declined';
|
||||
|
||||
// TODO: log the actual license seat that was checked out
|
||||
if($event->acceptance->checkoutable instanceof LicenseSeat) {
|
||||
$logaction->item()->associate($event->acceptance->checkoutable->license);
|
||||
}
|
||||
|
||||
$logaction->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the listeners for the subscriber.
|
||||
*
|
||||
* @param Illuminate\Events\Dispatcher $events
|
||||
*/
|
||||
public function subscribe($events)
|
||||
{
|
||||
$list = [
|
||||
'CheckoutableCheckedIn',
|
||||
'CheckoutableCheckedOut',
|
||||
'CheckoutAccepted',
|
||||
'CheckoutDeclined',
|
||||
];
|
||||
|
||||
foreach($list as $event) {
|
||||
$events->listen(
|
||||
'App\Events\\' . $event,
|
||||
'App\Listeners\LogListener@on' . $event
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Traits\Acceptable;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
@ -27,6 +28,8 @@ class Accessory extends SnipeModel
|
|||
];
|
||||
|
||||
use Searchable;
|
||||
|
||||
use Acceptable;
|
||||
|
||||
/**
|
||||
* The attributes that should be included when searching the model.
|
||||
|
@ -47,13 +50,6 @@ class Accessory extends SnipeModel
|
|||
'supplier' => ['name'],
|
||||
'location' => ['name']
|
||||
];
|
||||
|
||||
/**
|
||||
* Set static properties to determine which checkout/checkin handlers we should use
|
||||
*/
|
||||
public static $checkoutClass = CheckoutAccessoryNotification::class;
|
||||
public static $checkinClass = CheckinAccessoryNotification::class;
|
||||
|
||||
|
||||
/**
|
||||
* Accessory validation rules
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use App\Events\AssetCheckedOut;
|
||||
use App\Events\CheckoutableCheckedOut;
|
||||
use App\Exceptions\CheckoutNotAllowed;
|
||||
use App\Http\Traits\UniqueSerialTrait;
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Models\Traits\Acceptable;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Models\User;
|
||||
use App\Presenters\Presentable;
|
||||
use AssetPresenter;
|
||||
use Auth;
|
||||
|
@ -17,7 +21,6 @@ use Watson\Validating\ValidatingTrait;
|
|||
use DB;
|
||||
use App\Notifications\CheckinAssetNotification;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
|
||||
/**
|
||||
* Model for Assets.
|
||||
*
|
||||
|
@ -32,12 +35,20 @@ class Asset extends Depreciable
|
|||
const ASSET = 'asset';
|
||||
const USER = 'user';
|
||||
|
||||
const ACCEPTANCE_PENDING = 'pending';
|
||||
use Acceptable;
|
||||
|
||||
/**
|
||||
* Set static properties to determine which checkout/checkin handlers we should use
|
||||
*/
|
||||
public static $checkoutClass = CheckoutAssetNotification::class;
|
||||
public static $checkinClass = CheckinAssetNotification::class;
|
||||
* Run after the checkout acceptance was declined by the user
|
||||
*
|
||||
* @param User $acceptedBy
|
||||
* @param string $signature
|
||||
*/
|
||||
public function declinedCheckout(User $declinedBy, $signature) {
|
||||
$this->assigned_to = null;
|
||||
$this->assigned_type = null;
|
||||
$this->accepted = null;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -252,21 +263,11 @@ class Asset extends Depreciable
|
|||
$this->location_id = $target->id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the user have to confirm that they accept the asset?
|
||||
*
|
||||
* If so, set the acceptance-status to "pending".
|
||||
* This value is used in the unaccepted assets reports, for example
|
||||
*
|
||||
* @see https://github.com/snipe/snipe-it/issues/5772
|
||||
*/
|
||||
if ($this->requireAcceptance() && $target instanceof User) {
|
||||
$this->accepted = self::ACCEPTANCE_PENDING;
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
$this->logCheckout($note, $target);
|
||||
|
||||
event(new CheckoutableCheckedOut($this, $target, Auth::user(), $note));
|
||||
|
||||
$this->increment('checkout_counter', 1);
|
||||
return true;
|
||||
}
|
||||
|
|
114
app/Models/CheckoutAcceptance.php
Normal file
114
app/Models/CheckoutAcceptance.php
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class CheckoutAcceptance extends Model
|
||||
{
|
||||
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that should be mutated to dates.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dates = [
|
||||
'accepted_at',
|
||||
'declined_at',
|
||||
|
||||
'deleted_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* The resource that was is out
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\MorphTo
|
||||
*/
|
||||
public function checkoutable() {
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
/**
|
||||
* The user that the checkoutable was checked out to
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function assignedTo() {
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this checkout acceptance pending?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isPending() {
|
||||
return $this->accepted_at == null && $this->declined_at == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was the checkoutable checked out to this user?
|
||||
*
|
||||
* @param User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function isCheckedOutTo(User $user) {
|
||||
return $this->assignedTo->is($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept the checkout acceptance
|
||||
*
|
||||
* @param string $signature_filename
|
||||
*/
|
||||
public function accept($signature_filename) {
|
||||
$this->accepted_at = now();
|
||||
$this->signature_filename = $signature_filename;
|
||||
$this->save();
|
||||
|
||||
/**
|
||||
* Update state for the checked out item
|
||||
*/
|
||||
$this->checkoutable->acceptedCheckout($this->assignedTo, $signature_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decline the checkout acceptance
|
||||
*
|
||||
* @param string $signature_filename
|
||||
*/
|
||||
public function decline($signature_filename) {
|
||||
$this->declined_at = now();
|
||||
$this->signature_filename = $signature_filename;
|
||||
$this->save();
|
||||
|
||||
/**
|
||||
* Update state for the checked out item
|
||||
*/
|
||||
$this->checkoutable->declinedCheckout($this->assignedTo, $signature_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter checkout acceptences by the user
|
||||
* @param Illuminate\Database\Eloquent\Builder $query
|
||||
* @param User $user
|
||||
* @return Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeForUser(Builder $query, User $user) {
|
||||
return $query->where('assigned_to_id', $user->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter to only get pending acceptances
|
||||
* @param Illuminate\Database\Eloquent\Builder $query
|
||||
* @return Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopePending(Builder $query) {
|
||||
return $query->whereNull('accepted_at')->whereNull('declined_at');
|
||||
}
|
||||
}
|
|
@ -20,13 +20,6 @@ class Component extends SnipeModel
|
|||
|
||||
protected $dates = ['deleted_at', 'purchase_date'];
|
||||
protected $table = 'components';
|
||||
|
||||
/**
|
||||
* Set static properties to determine which checkout/checkin handlers we should use
|
||||
*/
|
||||
public static $checkoutClass = null;
|
||||
public static $checkinClass = null;
|
||||
|
||||
|
||||
/**
|
||||
* Category validation rules
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Traits\Acceptable;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
@ -14,18 +15,14 @@ class Consumable extends SnipeModel
|
|||
use Loggable, Presentable;
|
||||
use SoftDeletes;
|
||||
|
||||
use Acceptable;
|
||||
|
||||
protected $dates = ['deleted_at', 'purchase_date'];
|
||||
protected $table = 'consumables';
|
||||
protected $casts = [
|
||||
'requestable' => 'boolean'
|
||||
];
|
||||
|
||||
/**
|
||||
* Set static properties to determine which checkout/checkin handlers we should use
|
||||
*/
|
||||
public static $checkoutClass = CheckoutConsumableNotification::class;
|
||||
public static $checkinClass = null;
|
||||
|
||||
|
||||
/**
|
||||
* Category validation rules
|
||||
|
|
|
@ -12,9 +12,14 @@ use Illuminate\Validation\Rule;
|
|||
|
||||
class CustomField extends Model
|
||||
{
|
||||
use ValidatingTrait, UniqueUndeletedTrait;
|
||||
public $guarded=["id"];
|
||||
public static $PredefinedFormats=[
|
||||
use ValidatingTrait,
|
||||
UniqueUndeletedTrait;
|
||||
|
||||
public $guarded = [
|
||||
"id"
|
||||
];
|
||||
|
||||
public static $PredefinedFormats = [
|
||||
"ANY" => "",
|
||||
"CUSTOM REGEX" => "",
|
||||
"ALPHA" => "alpha",
|
||||
|
@ -31,6 +36,14 @@ class CustomField extends Model
|
|||
"BOOLEAN" => "boolean",
|
||||
];
|
||||
|
||||
/**
|
||||
* Validation rules.
|
||||
* At least empty array must be provided if using ValidatingTrait.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rules = [];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
|
@ -57,7 +70,6 @@ class CustomField extends Model
|
|||
*/
|
||||
public static $table_name = "assets";
|
||||
|
||||
|
||||
/**
|
||||
* Convert the custom field's name property to a db-safe string.
|
||||
*
|
||||
|
|
|
@ -7,10 +7,16 @@ use Watson\Validating\ValidatingTrait;
|
|||
|
||||
class CustomFieldset extends Model
|
||||
{
|
||||
use ValidatingTrait;
|
||||
|
||||
protected $guarded=["id"];
|
||||
|
||||
public $rules=[
|
||||
"name" => "required|unique:custom_fieldsets"
|
||||
/**
|
||||
* Validation rules
|
||||
* @var array
|
||||
*/
|
||||
protected $rules = [
|
||||
"name" => "required|unique:custom_fieldsets"
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -21,7 +27,6 @@ class CustomFieldset extends Model
|
|||
* @var boolean
|
||||
*/
|
||||
protected $injectUniqueIdentifier = true;
|
||||
use ValidatingTrait;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,12 +18,6 @@ class License extends Depreciable
|
|||
{
|
||||
protected $presenter = 'App\Presenters\LicensePresenter';
|
||||
|
||||
/**
|
||||
* Set static properties to determine which checkout/checkin handlers we should use
|
||||
*/
|
||||
public static $checkoutClass = CheckoutLicenseNotification::class;
|
||||
public static $checkinClass = CheckinLicenseNotification::class;
|
||||
|
||||
|
||||
use SoftDeletes;
|
||||
use CompanyableTrait;
|
||||
|
|
|
@ -2,32 +2,37 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Models\Loggable;
|
||||
use App\Models\Traits\Acceptable;
|
||||
use App\Notifications\CheckinLicenseNotification;
|
||||
use App\Notifications\CheckoutLicenseNotification;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use App\Notifications\CheckoutLicenseNotification;
|
||||
use App\Notifications\CheckinLicenseNotification;
|
||||
|
||||
class LicenseSeat extends Model implements ICompanyableChild
|
||||
class LicenseSeat extends SnipeModel implements ICompanyableChild
|
||||
{
|
||||
use CompanyableChildTrait;
|
||||
use SoftDeletes;
|
||||
use Loggable;
|
||||
|
||||
protected $presenter = 'App\Presenters\LicenseSeatPresenter';
|
||||
use Presentable;
|
||||
|
||||
protected $dates = ['deleted_at'];
|
||||
protected $guarded = 'id';
|
||||
protected $table = 'license_seats';
|
||||
|
||||
/**
|
||||
* Set static properties to determine which checkout/checkin handlers we should use
|
||||
*/
|
||||
public static $checkoutClass = CheckoutLicenseNotification::class;
|
||||
public static $checkinClass = CheckinLicenseNotification::class;
|
||||
use Acceptable;
|
||||
|
||||
public function getCompanyableParents()
|
||||
{
|
||||
return ['asset', 'license'];
|
||||
}
|
||||
|
||||
public function getEula() {
|
||||
return $this->license->getEula();
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the seat -> license relationship
|
||||
*
|
||||
|
|
|
@ -20,13 +20,13 @@ class Location extends SnipeModel
|
|||
protected $dates = ['deleted_at'];
|
||||
protected $table = 'locations';
|
||||
protected $rules = array(
|
||||
'name' => 'required|min:2|max:255|unique_undeleted',
|
||||
'city' => 'min:2|max:255|nullable',
|
||||
'country' => 'min:2|max:2|nullable',
|
||||
'name' => 'required|min:2|max:255|unique_undeleted',
|
||||
'city' => 'min:2|max:255|nullable',
|
||||
'country' => 'min:2|max:2|nullable',
|
||||
'address' => 'max:80|nullable',
|
||||
'address2' => 'max:80|nullable',
|
||||
'zip' => 'min:3|max:10|nullable',
|
||||
// 'manager_id' => 'exists:users'
|
||||
'zip' => 'min:3|max:10|nullable',
|
||||
'manager_id' => 'exists:users,id|nullable'
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -56,6 +56,7 @@ class Location extends SnipeModel
|
|||
'country',
|
||||
'zip',
|
||||
'ldap_ou',
|
||||
'manager_id',
|
||||
'currency',
|
||||
'image',
|
||||
];
|
||||
|
|
|
@ -6,14 +6,7 @@ use App\Models\Actionlog;
|
|||
use App\Models\Asset;
|
||||
use App\Models\CheckoutRequest;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckinAssetNotification;
|
||||
use App\Notifications\AuditNotification;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
use App\Notifications\CheckoutAccessoryNotification;
|
||||
use App\Notifications\CheckinAccessoryNotification;
|
||||
use App\Notifications\CheckoutConsumableNotification;
|
||||
use App\Notifications\CheckoutLicenseNotification;
|
||||
use App\Notifications\CheckinLicenseNotification;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
|
||||
|
@ -38,7 +31,6 @@ trait Loggable
|
|||
*/
|
||||
public function logCheckout($note, $target /* What are we checking out to? */)
|
||||
{
|
||||
$settings = Setting::getSettings();
|
||||
$log = new Actionlog;
|
||||
$log = $this->determineLogItemType($log);
|
||||
$log->user_id = Auth::user()->id;
|
||||
|
@ -63,29 +55,6 @@ trait Loggable
|
|||
$log->note = $note;
|
||||
$log->logaction('checkout');
|
||||
|
||||
$params = [
|
||||
'item' => $log->item,
|
||||
'target_type' => $log->target_type,
|
||||
'target' => $target,
|
||||
'admin' => $log->user,
|
||||
'note' => $note,
|
||||
'log_id' => $log->id,
|
||||
'settings' => $settings,
|
||||
];
|
||||
|
||||
$checkoutClass = null;
|
||||
|
||||
if (method_exists($target, 'notify')) {
|
||||
$target->notify(new static::$checkoutClass($params));
|
||||
}
|
||||
|
||||
// Send to the admin, if settings dictate
|
||||
$recipient = new \App\Models\Recipients\AdminRecipient();
|
||||
|
||||
if (($settings->admin_cc_email!='') && (static::$checkoutClass!='')) {
|
||||
$recipient->notify(new static::$checkoutClass($params));
|
||||
}
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
|
@ -112,7 +81,6 @@ trait Loggable
|
|||
*/
|
||||
public function logCheckin($target, $note)
|
||||
{
|
||||
$settings = Setting::getSettings();
|
||||
$log = new Actionlog;
|
||||
$log->target_type = get_class($target);
|
||||
$log->target_id = $target->id;
|
||||
|
@ -140,29 +108,6 @@ trait Loggable
|
|||
$log->user_id = Auth::user()->id;
|
||||
$log->logaction('checkin from');
|
||||
|
||||
$params = [
|
||||
'target' => $target,
|
||||
'item' => $log->item,
|
||||
'admin' => $log->user,
|
||||
'note' => $note,
|
||||
'target_type' => $log->target_type,
|
||||
'settings' => $settings,
|
||||
];
|
||||
|
||||
|
||||
$checkinClass = null;
|
||||
|
||||
if (method_exists($target, 'notify')) {
|
||||
$target->notify(new static::$checkinClass($params));
|
||||
}
|
||||
|
||||
// Send to the admin, if settings dictate
|
||||
$recipient = new \App\Models\Recipients\AdminRecipient();
|
||||
|
||||
if (($settings->admin_cc_email!='') && (static::$checkinClass!='')) {
|
||||
$recipient->notify(new static::$checkinClass($params));
|
||||
}
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Recipients;
|
||||
|
||||
use App\Models\Setting;
|
||||
|
||||
class AlertRecipient extends Recipient{
|
||||
|
||||
public function __construct()
|
||||
class AlertRecipient extends Recipient
|
||||
{
|
||||
public function __construct(string $email)
|
||||
{
|
||||
$settings = Setting::getSettings();
|
||||
$this->email = $settings->alert_email;
|
||||
$this->email = trim($email);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Recipients;
|
||||
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
abstract class Recipient {
|
||||
|
||||
abstract class Recipient
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
protected $email;
|
||||
|
||||
}
|
||||
|
|
31
app/Models/Traits/Acceptable.php
Normal file
31
app/Models/Traits/Acceptable.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Traits;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
* This trait allows models to have a callback after their checkout gets accepted or declined.
|
||||
*
|
||||
* @author Till Deeke <kontakt@tilldeeke.de>
|
||||
*/
|
||||
trait Acceptable {
|
||||
/**
|
||||
* Run after the checkout acceptance was accepted by the user
|
||||
*
|
||||
* @param User $acceptedBy
|
||||
* @param string $signature
|
||||
*/
|
||||
public function acceptedCheckout(User $acceptedBy, $signature) {}
|
||||
|
||||
/**
|
||||
* Run after the checkout acceptance was declined by the user
|
||||
*
|
||||
* @param User $acceptedBy
|
||||
* @param string $signature
|
||||
*/
|
||||
public function declinedCheckout(User $declinedBy, $signature) {}
|
||||
}
|
|
@ -126,12 +126,13 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
|
||||
$user_permissions = json_decode($this->permissions, true);
|
||||
|
||||
$is_user_section_permissions_set = ($user_permissions != '') && array_key_exists($section, $user_permissions);
|
||||
//If the user is explicitly granted, return true
|
||||
if (($user_permissions!='') && ((array_key_exists($section, $user_permissions)) && ($user_permissions[$section]=='1'))) {
|
||||
if ($is_user_section_permissions_set && ($user_permissions[$section]=='1')) {
|
||||
return true;
|
||||
}
|
||||
// If the user is explicitly denied, return false
|
||||
if (($user_permissions=='') || array_key_exists($section, $user_permissions) && ($user_permissions[$section]=='-1')) {
|
||||
if ($is_user_section_permissions_set && ($user_permissions[$section]=='-1')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use App\Models\User;
|
||||
|
@ -15,31 +16,19 @@ use Illuminate\Support\Facades\Mail;
|
|||
class CheckinAccessoryNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $params;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
public function __construct(Accessory $accessory, $checkedOutTo, User $checkedInby, $note)
|
||||
{
|
||||
$this->target = $params['target'];
|
||||
$this->item = $params['item'];
|
||||
$this->admin = $params['admin'];
|
||||
$this->note = '';
|
||||
$this->target_type = $params['target'];
|
||||
$this->settings = $params['settings'];
|
||||
|
||||
if (array_key_exists('note', $params)) {
|
||||
$this->note = $params['note'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
$this->item = $accessory;
|
||||
$this->target = $checkedOutTo;
|
||||
$this->admin = $checkedInby;
|
||||
$this->note = $note;
|
||||
$this->settings = Setting::getSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use App\Models\User;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class CheckinAssetNotification extends Notification
|
||||
{
|
||||
|
@ -20,19 +21,15 @@ class CheckinAssetNotification extends Notification
|
|||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
public function __construct(Asset $asset, $checkedOutTo, User $checkedInBy, $note)
|
||||
{
|
||||
$this->target = $params['target'];
|
||||
$this->item = $params['item'];
|
||||
$this->admin = $params['admin'];
|
||||
$this->note = '';
|
||||
$this->expected_checkin = '';
|
||||
$this->target_type = $params['target_type'];
|
||||
$this->settings = $params['settings'];
|
||||
$this->target = $checkedOutTo;
|
||||
$this->item = $asset;
|
||||
$this->admin = $checkedInBy;
|
||||
$this->note = $note;
|
||||
|
||||
if (array_key_exists('note', $params)) {
|
||||
$this->note = $params['note'];
|
||||
}
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->expected_checkin = '';
|
||||
|
||||
if ($this->item->expected_checkin) {
|
||||
$this->expected_checkin = \App\Helpers\Helper::getFormattedDateObject($this->item->expected_checkin, 'date',
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\License;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use App\Models\User;
|
||||
|
@ -12,7 +14,7 @@ use Illuminate\Notifications\Messages\SlackMessage;
|
|||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class CheckinLicenseNotification extends Notification
|
||||
class CheckinLicenseSeatNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
/**
|
||||
|
@ -25,19 +27,13 @@ class CheckinLicenseNotification extends Notification
|
|||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
public function __construct(LicenseSeat $licenseSeat, $checkedOutTo, User $checkedInBy, $note)
|
||||
{
|
||||
$this->target = $params['target'];
|
||||
$this->item = $params['item'];
|
||||
$this->admin = $params['admin'];
|
||||
$this->note = '';
|
||||
$this->settings = $params['settings'];
|
||||
$this->target_type = $params['target_type'];
|
||||
|
||||
if (array_key_exists('note', $params)) {
|
||||
$this->note = $params['note'];
|
||||
}
|
||||
|
||||
$this->target = $checkedOutTo;
|
||||
$this->item = $licenseSeat->license;
|
||||
$this->admin = $checkedInBy;
|
||||
$this->note = $note;
|
||||
$this->settings = Setting::getSettings();
|
||||
}
|
||||
|
||||
/**
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use App\Models\User;
|
||||
|
@ -15,33 +16,20 @@ use Illuminate\Support\Facades\Mail;
|
|||
class CheckoutAccessoryNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $params;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
public function __construct(Accessory $accessory, $checkedOutTo, User $checkedOutBy, $acceptance, $note)
|
||||
{
|
||||
$this->target = $params['target'];
|
||||
$this->item = $params['item'];
|
||||
$this->admin = $params['admin'];
|
||||
$this->log_id = $params['log_id'];
|
||||
$this->note = '';
|
||||
$this->last_checkout = '';
|
||||
$this->expected_checkin = '';
|
||||
$this->target_type = $params['target_type'];
|
||||
$this->settings = $params['settings'];
|
||||
|
||||
if (array_key_exists('note', $params)) {
|
||||
$this->note = $params['note'];
|
||||
}
|
||||
|
||||
|
||||
$this->item = $accessory;
|
||||
$this->admin = $checkedOutBy;
|
||||
$this->note = $note;
|
||||
$this->target = $checkedOutTo;
|
||||
$this->acceptance = $acceptance;
|
||||
|
||||
$this->settings = Setting::getSettings();
|
||||
|
||||
}
|
||||
|
||||
|
@ -132,6 +120,8 @@ class CheckoutAccessoryNotification extends Notification
|
|||
$eula = $this->item->getEula();
|
||||
$req_accept = $this->item->requireAcceptance();
|
||||
|
||||
$accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance);
|
||||
|
||||
return (new MailMessage)->markdown('notifications.markdown.checkout-accessory',
|
||||
[
|
||||
'item' => $this->item,
|
||||
|
@ -140,7 +130,7 @@ class CheckoutAccessoryNotification extends Notification
|
|||
'target' => $this->target,
|
||||
'eula' => $eula,
|
||||
'req_accept' => $req_accept,
|
||||
'accept_url' => url('/').'/account/accept-asset/'.$this->log_id,
|
||||
'accept_url' => $accept_url,
|
||||
])
|
||||
->subject(trans('mail.Confirm_accessory_delivery'));
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
|
@ -13,31 +14,25 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
|||
class CheckoutAssetNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $params;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
public function __construct(Asset $asset, $checkedOutTo, User $checkedOutBy, $acceptance, $note)
|
||||
{
|
||||
$this->target = $params['target'];
|
||||
$this->item = $params['item'];
|
||||
$this->admin = $params['admin'];
|
||||
$this->log_id = $params['log_id'];
|
||||
$this->note = '';
|
||||
|
||||
$this->item = $asset;
|
||||
$this->admin = $checkedOutBy;
|
||||
$this->note = $note;
|
||||
$this->target = $checkedOutTo;
|
||||
$this->acceptance = $acceptance;
|
||||
|
||||
$this->settings = Setting::getSettings();
|
||||
|
||||
$this->last_checkout = '';
|
||||
$this->expected_checkin = '';
|
||||
$this->target_type = $params['target_type'];
|
||||
$this->settings = $params['settings'];
|
||||
|
||||
if (array_key_exists('note', $params)) {
|
||||
$this->note = $params['note'];
|
||||
}
|
||||
|
||||
if ($this->item->last_checkout) {
|
||||
$this->last_checkout = \App\Helpers\Helper::getFormattedDateObject($this->item->last_checkout, 'date',
|
||||
|
@ -146,17 +141,18 @@ class CheckoutAssetNotification extends Notification
|
|||
$fields = $this->item->model->fieldset->fields;
|
||||
}
|
||||
|
||||
$accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance);
|
||||
|
||||
$message = (new MailMessage)->markdown('notifications.markdown.checkout-asset',
|
||||
[
|
||||
'item' => $this->item,
|
||||
'admin' => $this->admin,
|
||||
'note' => $this->note,
|
||||
'log_id' => $this->note,
|
||||
'target' => $this->target,
|
||||
'fields' => $fields,
|
||||
'eula' => $eula,
|
||||
'req_accept' => $req_accept,
|
||||
'accept_url' => url('/').'/account/accept-asset/'.$this->log_id,
|
||||
'accept_url' => $accept_url,
|
||||
'last_checkout' => $this->last_checkout,
|
||||
'expected_checkin' => $this->expected_checkin,
|
||||
])
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Consumable;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use App\Models\User;
|
||||
|
@ -25,21 +26,16 @@ class CheckoutConsumableNotification extends Notification
|
|||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
public function __construct(Consumable $consumable, $checkedOutTo, User $checkedOutBy, $acceptance, $note)
|
||||
{
|
||||
$this->target = $params['target'];
|
||||
$this->item = $params['item'];
|
||||
$this->admin = $params['admin'];
|
||||
$this->log_id = $params['log_id'];
|
||||
$this->note = '';
|
||||
$this->last_checkout = '';
|
||||
$this->expected_checkin = '';
|
||||
$this->target_type = $params['target_type'];
|
||||
$this->settings = $params['settings'];
|
||||
|
||||
if (array_key_exists('note', $params)) {
|
||||
$this->note = $params['note'];
|
||||
}
|
||||
$this->item = $consumable;
|
||||
$this->admin = $checkedOutBy;
|
||||
$this->note = $note;
|
||||
$this->target = $checkedOutTo;
|
||||
$this->acceptance = $acceptance;
|
||||
|
||||
$this->settings = Setting::getSettings();
|
||||
|
||||
}
|
||||
|
||||
|
@ -126,16 +122,17 @@ class CheckoutConsumableNotification extends Notification
|
|||
$eula = $this->item->getEula();
|
||||
$req_accept = $this->item->requireAcceptance();
|
||||
|
||||
$accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance);
|
||||
|
||||
return (new MailMessage)->markdown('notifications.markdown.checkout-consumable',
|
||||
[
|
||||
'item' => $this->item,
|
||||
'admin' => $this->admin,
|
||||
'note' => $this->note,
|
||||
'log_id' => $this->note,
|
||||
'target' => $this->target,
|
||||
'eula' => $eula,
|
||||
'req_accept' => $req_accept,
|
||||
'accept_url' => url('/').'/account/accept-asset/'.$this->log_id,
|
||||
'accept_url' => $accept_url,
|
||||
])
|
||||
->subject(trans('mail.Confirm_consumable_delivery'));
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\License;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use App\Models\User;
|
||||
|
@ -12,7 +14,7 @@ use Illuminate\Notifications\Messages\SlackMessage;
|
|||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class CheckoutLicenseNotification extends Notification
|
||||
class CheckoutLicenseSeatNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
/**
|
||||
|
@ -25,23 +27,15 @@ class CheckoutLicenseNotification extends Notification
|
|||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
public function __construct(LicenseSeat $licenseSeat, $checkedOutTo, User $checkedOutBy, $acceptance, $note)
|
||||
{
|
||||
$this->target = $params['target'];
|
||||
$this->item = $params['item'];
|
||||
$this->admin = $params['admin'];
|
||||
$this->log_id = $params['log_id'];
|
||||
$this->note = '';
|
||||
$this->target_type = $params['target_type'];
|
||||
$this->settings = $params['settings'];
|
||||
$this->target_type = $params['target_type'];
|
||||
|
||||
if (array_key_exists('note', $params)) {
|
||||
$this->note = $params['note'];
|
||||
}
|
||||
|
||||
|
||||
$this->item = $licenseSeat->license;
|
||||
$this->admin = $checkedOutBy;
|
||||
$this->note = $note;
|
||||
$this->target = $checkedOutTo;
|
||||
$this->acceptance = $acceptance;
|
||||
|
||||
$this->settings = Setting::getSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,6 +119,8 @@ class CheckoutLicenseNotification extends Notification
|
|||
$eula = method_exists($this->item, 'getEula') ? $this->item->getEula() : '';
|
||||
$req_accept = method_exists($this->item, 'requireAcceptance') ? $this->item->requireAcceptance() : 0;
|
||||
|
||||
$accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance);
|
||||
|
||||
return (new MailMessage)->markdown('notifications.markdown.checkout-license',
|
||||
[
|
||||
'item' => $this->item,
|
||||
|
@ -133,7 +129,7 @@ class CheckoutLicenseNotification extends Notification
|
|||
'target' => $this->target,
|
||||
'eula' => $eula,
|
||||
'req_accept' => $req_accept,
|
||||
'accept_url' => url('/').'/account/accept-asset/'.$this->log_id,
|
||||
'accept_url' => $accept_url,
|
||||
])
|
||||
->subject(trans('mail.Confirm_license_delivery'));
|
||||
|
|
@ -3,8 +3,8 @@
|
|||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class InventoryAlert extends Notification
|
||||
{
|
||||
|
@ -33,14 +33,13 @@ class InventoryAlert extends Notification
|
|||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
$notifyBy = [];
|
||||
$notifyBy[]='mail';
|
||||
$notifyBy[] = 'mail';
|
||||
|
||||
return $notifyBy;
|
||||
}
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,17 +50,16 @@ class InventoryAlert extends Notification
|
|||
*/
|
||||
public function toMail($params)
|
||||
{
|
||||
|
||||
$message = (new MailMessage)->markdown('notifications.markdown.report-low-inventory',
|
||||
$message = (new MailMessage)->markdown(
|
||||
'notifications.markdown.report-low-inventory',
|
||||
[
|
||||
'items' => $this->items,
|
||||
'threshold' => $this->threshold,
|
||||
])
|
||||
]
|
||||
)
|
||||
->subject(trans('mail.Low_Inventory_Report'));
|
||||
|
||||
return $message;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
18
app/Presenters/LicenseSeatPresenter.php
Normal file
18
app/Presenters/LicenseSeatPresenter.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Presenters;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* Class LicensePresenter
|
||||
* @package App\Presenters
|
||||
*/
|
||||
class LicenseSeatPresenter extends Presenter
|
||||
{
|
||||
public function name()
|
||||
{
|
||||
return $this->model->license->name;
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use App\Listeners\CheckoutableListener;
|
||||
use App\Listeners\LogListener;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
|
@ -23,6 +25,15 @@ class EventServiceProvider extends ServiceProvider
|
|||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The subscriber classes to register.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $subscribe = [
|
||||
LogListener::class,
|
||||
CheckoutableListener::class
|
||||
];
|
||||
|
||||
/**
|
||||
* Register any events for your application.
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCheckoutAcceptancesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('checkout_acceptances', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
|
||||
$table->morphs('checkoutable');
|
||||
$table->integer('assigned_to_id')->unsigned();
|
||||
|
||||
$table->string('signature_filename')->nullable();
|
||||
|
||||
$table->timestamp('accepted_at')->nullable();
|
||||
$table->timestamp('declined_at')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('checkout_acceptances');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Actionlog;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateCheckoutAcceptancesForUnacceptedAssets extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// Get all assets not accepted
|
||||
$assets = DB::table('assets')->where('assigned_type', 'App\Models\User')->where('accepted', 'pending')->get();
|
||||
|
||||
$acceptances = [];
|
||||
|
||||
foreach($assets as $asset) {
|
||||
$acceptances[] = [
|
||||
'checkoutable_type' => 'App\Models\Asset',
|
||||
'checkoutable_id' => $asset->id,
|
||||
'assigned_to_id' => $asset->assigned_to,
|
||||
];
|
||||
}
|
||||
|
||||
DB::table('checkout_acceptances')->insert($acceptances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
|
@ -17,8 +17,24 @@ else
|
|||
fi
|
||||
|
||||
# create data directories
|
||||
for dir in 'data/private_uploads' 'data/uploads' 'data/uploads/avatars' 'data/uploads/barcodes' 'data/uploads/categories' 'data/uploads/companies' 'data/uploads/departments' 'data/uploads/locations' 'data/uploads/manufacturers' 'data/uploads/models' 'data/uploads/suppliers' 'dumps' 'keys'; do
|
||||
mkdir -p "/var/lib/snipeit/$dir"
|
||||
for dir in \
|
||||
'data/private_uploads' \
|
||||
'data/uploads/accessories' \
|
||||
'data/uploads/avatars' \
|
||||
'data/uploads/barcodes' \
|
||||
'data/uploads/categories' \
|
||||
'data/uploads/companies' \
|
||||
'data/uploads/components' \
|
||||
'data/uploads/consumables' \
|
||||
'data/uploads/departments' \
|
||||
'data/uploads/locations' \
|
||||
'data/uploads/manufacturers' \
|
||||
'data/uploads/models' \
|
||||
'data/uploads/suppliers' \
|
||||
'dumps' \
|
||||
'keys'
|
||||
do
|
||||
[ ! -d "/var/lib/snipeit/$dir" ] && mkdir -p "/var/lib/snipeit/$dir"
|
||||
done
|
||||
|
||||
chown -R docker:root /var/lib/snipeit/data/*
|
||||
|
@ -26,9 +42,10 @@ chown -R docker:root /var/lib/snipeit/dumps
|
|||
chown -R docker:root /var/lib/snipeit/keys
|
||||
|
||||
# If the Oauth DB files are not present copy the vendor files over to the db migrations
|
||||
if [ ! -f "/var/www/html/database/migrations/*create_oauth*" ]; then
|
||||
if [ ! -f "/var/www/html/database/migrations/*create_oauth*" ]
|
||||
then
|
||||
cp -ax /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/
|
||||
fi
|
||||
|
||||
. /etc/apache2/envvars
|
||||
. /etc/apache2/envvars
|
||||
exec apache2 -DNO_DETACH < /dev/null
|
||||
|
|
54
phpmd.xml
Normal file
54
phpmd.xml
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ruleset name="Laravel and similar phpmd ruleset"
|
||||
xmlns="http://pmd.sf.net/ruleset/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
|
||||
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
|
||||
<description>
|
||||
Inspired by https://github.com/phpmd/phpmd/issues/137
|
||||
using http://phpmd.org/documentation/creating-a-ruleset.html
|
||||
</description>
|
||||
<!-- se importan los rulesets, en este caso todos. -->
|
||||
<rule ref="rulesets/cleancode.xml">
|
||||
<exclude name="StaticAccess"/>
|
||||
</rule>
|
||||
<rule ref="rulesets/codesize.xml/CyclomaticComplexity"/>
|
||||
<rule ref="rulesets/codesize.xml/NPathComplexity"/>
|
||||
<rule ref="rulesets/codesize.xml/ExcessiveMethodLength"/>
|
||||
<rule ref="rulesets/codesize.xml/ExcessiveClassLength"/>
|
||||
<rule ref="rulesets/codesize.xml/ExcessiveParameterList"/>
|
||||
<rule ref="rulesets/codesize.xml/ExcessivePublicCount"/>
|
||||
<rule ref="rulesets/codesize.xml/TooManyFields"/>
|
||||
<rule ref="rulesets/codesize.xml/TooManyMethods">
|
||||
<properties>
|
||||
<property name="maxmethods" value="30"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="rulesets/codesize.xml/ExcessiveClassComplexity"/>
|
||||
<rule ref="rulesets/controversial.xml"/>
|
||||
<rule ref="rulesets/design.xml">
|
||||
<exclude name="CouplingBetweenObjects"/>
|
||||
</rule>
|
||||
<!-- beware the façades yo. -->
|
||||
<rule ref="rulesets/design.xml/CouplingBetweenObjects">
|
||||
<properties>
|
||||
<property name="minimum" value="20"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<!-- se importa naming y se excluye ShortVariable para ser ajustada despues. -->
|
||||
<rule ref="rulesets/naming.xml">
|
||||
<exclude name="ShortVariable"/>
|
||||
</rule>
|
||||
<rule ref="rulesets/naming.xml/ShortVariable"
|
||||
since="0.2"
|
||||
message="Avoid variables with short names like {0}. Configured minimum length is {1}."
|
||||
class="PHPMD\Rule\Naming\ShortVariable"
|
||||
externalInfoUrl="http://phpmd.org/rules/naming.html#shortvariable">
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
<property name="minimum" description="Minimum length for a variable, property or parameter name" value="3"/>
|
||||
<property name="exceptions" value="id,q,w,i,j,v,e,f,fp" />
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="rulesets/unusedcode.xml"/>
|
||||
</ruleset>
|
135
resources/views/account/accept/create.blade.php
Normal file
135
resources/views/account/accept/create.blade.php
Normal file
|
@ -0,0 +1,135 @@
|
|||
@extends('layouts/default')
|
||||
|
||||
{{-- Page title --}}
|
||||
@section('title')
|
||||
Accept {{ $acceptance->checkoutable->present()->name() }}
|
||||
@parent
|
||||
@stop
|
||||
|
||||
|
||||
{{-- Page content --}}
|
||||
@section('content')
|
||||
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('css/signature-pad.css') }}">
|
||||
|
||||
<style>
|
||||
.form-horizontal .control-label, .form-horizontal .radio, .form-horizontal .checkbox, .form-horizontal .radio-inline, .form-horizontal .checkbox-inline {
|
||||
padding-top: 17px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#eula_div {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
<form class="form-horizontal" method="post" action="" autocomplete="off">
|
||||
<!-- CSRF Token -->
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2">
|
||||
<div class="panel box box-default">
|
||||
<div class="box-body">
|
||||
<div class="col-md-12">
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="asset_acceptance" id="accepted" value="accepted">
|
||||
I accept
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="asset_acceptance" id="declined" value="declined">
|
||||
I decline
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@if ($acceptance->checkoutable->getEula())
|
||||
<div class="col-md-12" style="padding-top: 20px">
|
||||
<div id="eula_div">
|
||||
{!! $acceptance->checkoutable->getEula() !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($snipeSettings->require_accept_signature=='1')
|
||||
<div class="col-md-12 col-sm-12 text-center" style="padding-top: 20px">
|
||||
|
||||
<h3>Sign below to indicate that you agree to the terms of service:</h3>
|
||||
|
||||
<div id="signature-pad" class="m-signature-pad">
|
||||
<div class="m-signature-pad--body col-md-12 col-sm-12 col-lg-12 col-xs-12">
|
||||
<canvas></canvas>
|
||||
<input type="hidden" name="signature_output" id="signature_output">
|
||||
</div>
|
||||
<div class="col-md-12 col-sm-12 col-lg-12 col-xs-12 text-center">
|
||||
<button type="button" class="btn btn-sm btn-default clear" data-action="clear" id="clear_button">Clear Signature</button>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- .col-md-12.text-center-->
|
||||
@endif
|
||||
|
||||
</div><!-- / col-md-12 -->
|
||||
|
||||
</div> <!-- / box-body -->
|
||||
<div class="box-footer text-right">
|
||||
<button type="submit" class="btn btn-success" id="submit-button"><i class="fa fa-check icon-white"></i> {{ trans('general.submit') }}</button>
|
||||
</div><!-- /.box-footer -->
|
||||
</div> <!-- / box-default -->
|
||||
</div> <!-- / col -->
|
||||
</div> <!-- / row -->
|
||||
</form>
|
||||
|
||||
@stop
|
||||
|
||||
@section('moar_scripts')
|
||||
|
||||
<script src="{{ asset('js/signature_pad.min.js') }}"></script>
|
||||
<script nonce="{{ csrf_token() }}">
|
||||
var wrapper = document.getElementById("signature-pad"),
|
||||
clearButton = wrapper.querySelector("[data-action=clear]"),
|
||||
saveButton = wrapper.querySelector("[data-action=save]"),
|
||||
canvas = wrapper.querySelector("canvas"),
|
||||
signaturePad;
|
||||
|
||||
// Adjust canvas coordinate space taking into account pixel ratio,
|
||||
// to make it look crisp on mobile devices.
|
||||
// This also causes canvas to be cleared.
|
||||
function resizeCanvas() {
|
||||
// When zoomed out to less than 100%, for some very strange reason,
|
||||
// some browsers report devicePixelRatio as less than 1
|
||||
// and only part of the canvas is cleared then.
|
||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||
canvas.width = canvas.offsetWidth * ratio;
|
||||
canvas.height = canvas.offsetHeight * ratio;
|
||||
canvas.getContext("2d").scale(ratio, ratio);
|
||||
}
|
||||
|
||||
window.onresize = resizeCanvas;
|
||||
resizeCanvas();
|
||||
|
||||
signaturePad = new SignaturePad(canvas);
|
||||
|
||||
$('#clear_button').on("click", function (event) {
|
||||
signaturePad.clear();
|
||||
});
|
||||
|
||||
$('#submit-button').on("click", function (event) {
|
||||
if (signaturePad.isEmpty()) {
|
||||
alert("Please provide signature first.");
|
||||
return false;
|
||||
} else {
|
||||
$('#signature_output').val(signaturePad.toDataURL());
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
@stop
|
61
resources/views/account/accept/index.blade.php
Executable file
61
resources/views/account/accept/index.blade.php
Executable file
|
@ -0,0 +1,61 @@
|
|||
@extends('layouts/default')
|
||||
|
||||
{{-- Page title --}}
|
||||
@section('title')
|
||||
Accept assets {{ $user->present()->fullName() }}
|
||||
@parent
|
||||
@stop
|
||||
|
||||
{{-- Account page content --}}
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-default">
|
||||
|
||||
<div class="box-body">
|
||||
<!-- checked out Accessories table -->
|
||||
|
||||
<div class="table-responsive">
|
||||
<table
|
||||
data-cookie-id-table="pendingAcceptances"
|
||||
data-pagination="true"
|
||||
data-id-table="pendingAcceptances"
|
||||
data-search="true"
|
||||
data-side-pagination="client"
|
||||
data-show-columns="true"
|
||||
data-show-export="true"
|
||||
data-show-refresh="true"
|
||||
data-sort-order="asc"
|
||||
id="pendingAcceptances"
|
||||
class="table table-striped snipe-table"
|
||||
data-export-options='{
|
||||
"fileName": "my-pending-acceptances-{{ date('Y-m-d') }}",
|
||||
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
|
||||
}'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($acceptances as $acceptance)
|
||||
<tr>
|
||||
<td>{{ $acceptance->checkoutable->present()->name }}</td>
|
||||
<td><a href="{{ route('account.accept.item', $acceptance) }}" class="btn btn-default btn-sm">Accept/Decline</a></td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div> <!-- .box-body-->
|
||||
</div><!--.box.box-default-->
|
||||
</div> <!-- .col-md-12-->
|
||||
</div> <!-- .row-->
|
||||
|
||||
@stop
|
||||
|
||||
@section('moar_scripts')
|
||||
@include ('partials.bootstrap-table')
|
||||
@stop
|
|
@ -59,8 +59,10 @@
|
|||
<label>
|
||||
<input type="checkbox" value="1" name="update_location" class="minimal" {{ Input::old('update_location') == '1' ? ' checked="checked"' : '' }}> Update asset location
|
||||
</label>
|
||||
sdd
|
||||
<p class="help-block">Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log.</p>
|
||||
|
||||
<a href="#" class="text-dark-gray" tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="<i class='fa fa-life-ring'></i> More Info" data-html="true" data-content="Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log.<br><br>Note that is this asset is checked out, it will not change the location of the person, asset or location it is checked out to."><i class="fa fa-life-ring"></i></a>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
<div class="col-sm-offset-3 col-md-9">
|
||||
<label>
|
||||
<input type="checkbox" value="1" name="update_location" class="minimal" {{ Input::old('update_location') == '1' ? ' checked="checked"' : '' }}> Update asset location
|
||||
</label> <a href="#" class="text-dark-gray" tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="More Info" data-html="true" data-content="Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log.<br><br>Note that is this asset is checked out, it will not change the location of the person, asset or location it is checked out to."><i class="fa fa-life-ring"></i></a>
|
||||
</label> <a href="#" class="text-dark-gray" tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="<i class='fa fa-life-ring'></i> More Info" data-html="true" data-content="Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log.<br><br>Note that is this asset is checked out, it will not change the location of the person, asset or location it is checked out to."><i class="fa fa-life-ring"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -309,7 +309,11 @@
|
|||
<i class="fa fa-check fa-disk fa-fw"></i>
|
||||
Requested Assets
|
||||
</a></li>
|
||||
|
||||
<li {!! (Request::is('account/accept') ? ' class="active"' : '') !!}>
|
||||
<a href="{{ route('account.accept') }}">
|
||||
<i class="fa fa-check fa-disk fa-fw"></i>
|
||||
Accept Assets
|
||||
</a></li>
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
{{ $model->manufacturer->name }}
|
||||
@endcan
|
||||
</li>
|
||||
@endif
|
||||
|
||||
@if ($model->manufacturer->url)
|
||||
<li>
|
||||
<i class="fa fa-globe"></i> <a href="{{ $model->manufacturer->url }}">{{ $model->manufacturer->url }}</a>
|
||||
|
@ -138,7 +138,7 @@
|
|||
<i class="fa fa-envelope"></i> <a href="mailto:{{ $model->manufacturer->support_email }}">{{ $model->manufacturer->support_email }}</a>
|
||||
</li>
|
||||
@endif
|
||||
|
||||
@endif
|
||||
@if ($model->model_number)
|
||||
<li>
|
||||
{{ trans('general.model_no') }}:
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<tr>
|
||||
<td align="center">
|
||||
<table class="content" width="100%" cellpadding="0" cellspacing="0">
|
||||
{{ $header or '' }}
|
||||
{{ $header ?? '' }}
|
||||
|
||||
<!-- Email Body -->
|
||||
<tr>
|
||||
|
@ -42,14 +42,14 @@
|
|||
<td class="content-cell">
|
||||
{{ Illuminate\Mail\Markdown::parse($slot) }}
|
||||
|
||||
{{ $subcopy or '' }}
|
||||
{{ $subcopy ?? '' }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{ $footer or '' }}
|
||||
{{ $footer ?? '' }}
|
||||
|
||||
</table>
|
||||
</td>
|
||||
|
@ -57,3 +57,4 @@
|
|||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -251,10 +251,6 @@ Route::group([ 'prefix' => 'account', 'middleware' => ['auth']], function () {
|
|||
'accept-asset/{logID}',
|
||||
[ 'as' => 'account/accept-assets', 'uses' => 'ViewAssetsController@getAcceptAsset' ]
|
||||
);
|
||||
Route::post(
|
||||
'accept-asset/{logID}',
|
||||
[ 'as' => 'account/asset-accepted', 'uses' => 'ViewAssetsController@postAcceptAsset' ]
|
||||
);
|
||||
|
||||
# Profile
|
||||
Route::get(
|
||||
|
@ -274,6 +270,15 @@ Route::group([ 'prefix' => 'account', 'middleware' => ['auth']], function () {
|
|||
# Account Dashboard
|
||||
Route::get('/', [ 'as' => 'account', 'uses' => 'ViewAssetsController@getIndex' ]);
|
||||
|
||||
|
||||
Route::get('accept', 'Account\AcceptanceController@index')
|
||||
->name('account.accept');
|
||||
|
||||
Route::get('accept/{id}', 'Account\AcceptanceController@create')
|
||||
->name('account.accept.item');
|
||||
|
||||
Route::post('accept/{id}', 'Account\AcceptanceController@store');
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -39,11 +39,11 @@ class DepreciationTest extends BaseTest
|
|||
{
|
||||
$category = $this->createValidCategory('license-graphics-category');
|
||||
$depreciation = $this->createValidDepreciation('computer', ['name' => 'New Depreciation']);
|
||||
$licenses = factory(App\Models\License::class, 5)->states('photoshop')->create([
|
||||
$licenses = factory(App\Models\LicenseModel::class, 5)->states('photoshop')->create([
|
||||
'depreciation_id'=>$depreciation->id,
|
||||
'category_id' => $category->id
|
||||
]);
|
||||
|
||||
$this->assertEquals(5,$depreciation->has_licenses());
|
||||
$this->assertEquals(5,$depreciation->licenses()->count());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue