Merge branch 'develop' into livewire_importer_2_squashed_and_rebased

I'll be taking in the changes to the importer front-end elsewhere
This commit is contained in:
Brady Wetherington 2023-03-07 18:51:05 -08:00
commit 09c1298e03
60 changed files with 1515 additions and 1137 deletions

21
.github/workflows/crowdin-upload.yml vendored Normal file
View file

@ -0,0 +1,21 @@
name: Crowdin Action
on:
push:
branches: [ develop ]
jobs:
upload-sources-to-crowdin:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Crowdin push
uses: crowdin/github-action@v1
with:
upload_sources: true
upload_translations: false
download_translations: false
project_id: ${{ secrets.CROWDIN_PROJECT_ID }}
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

View file

@ -6,6 +6,7 @@ use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use App\Helpers\Helper; use App\Helpers\Helper;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
use Log; use Log;
use Throwable; use Throwable;
use JsonException; use JsonException;
@ -28,6 +29,7 @@ class Handler extends ExceptionHandler
\Intervention\Image\Exception\NotSupportedException::class, \Intervention\Image\Exception\NotSupportedException::class,
\League\OAuth2\Server\Exception\OAuthServerException::class, \League\OAuth2\Server\Exception\OAuthServerException::class,
JsonException::class, JsonException::class,
SCIMException::class, //these generally don't need to be reported
]; ];
/** /**
@ -53,7 +55,7 @@ class Handler extends ExceptionHandler
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Exception $e * @param \Exception $e
* @return \Illuminate\Http\Response * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Http\Response
*/ */
public function render($request, Throwable $e) public function render($request, Throwable $e)
{ {
@ -70,6 +72,9 @@ class Handler extends ExceptionHandler
return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid JSON'), 422); return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid JSON'), 422);
} }
if ($e instanceof SCIMException) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid SCIM Request'), 400);
}
// Handle Ajax requests that fail because the model doesn't exist // Handle Ajax requests that fail because the model doesn't exist
if ($request->ajax() || $request->wantsJson()) { if ($request->ajax() || $request->wantsJson()) {
@ -113,8 +118,8 @@ class Handler extends ExceptionHandler
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception * @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\Response * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/ */
protected function unauthenticated($request, AuthenticationException $exception) protected function unauthenticated($request, AuthenticationException $exception)
{ {
if ($request->expectsJson()) { if ($request->expectsJson()) {

View file

@ -101,6 +101,7 @@ class AssetsController extends Controller
'checkin_counter', 'checkin_counter',
'requests_counter', 'requests_counter',
'byod', 'byod',
'asset_eol_date',
]; ];
$filter = []; $filter = [];
@ -128,7 +129,6 @@ class AssetsController extends Controller
// They are also used by the individual searches on detail pages like // They are also used by the individual searches on detail pages like
// locations, etc. // locations, etc.
// Search custom fields by column name // Search custom fields by column name
foreach ($all_custom_fields as $field) { foreach ($all_custom_fields as $field) {
if ($request->filled($field->db_column_name())) { if ($request->filled($field->db_column_name())) {
@ -136,7 +136,6 @@ class AssetsController extends Controller
} }
} }
if ($request->filled('status_id')) { if ($request->filled('status_id')) {
$assets->where('assets.status_id', '=', $request->input('status_id')); $assets->where('assets.status_id', '=', $request->input('status_id'));
} }
@ -173,6 +172,10 @@ class AssetsController extends Controller
$assets->where('assets.supplier_id', '=', $request->input('supplier_id')); $assets->where('assets.supplier_id', '=', $request->input('supplier_id'));
} }
if ($request->filled('asset_eol_date')) {
$assets->where('assets.asset_eol_date', '=', $request->input('asset_eol_date'));
}
if (($request->filled('assigned_to')) && ($request->filled('assigned_type'))) { if (($request->filled('assigned_to')) && ($request->filled('assigned_type'))) {
$assets->where('assets.assigned_to', '=', $request->input('assigned_to')) $assets->where('assets.assigned_to', '=', $request->input('assigned_to'))
->where('assets.assigned_type', '=', $request->input('assigned_type')); ->where('assets.assigned_type', '=', $request->input('assigned_type'));

View file

@ -126,7 +126,14 @@ class ImportController extends Controller
} }
$file_name = date('Y-m-d-his').'-'.$fixed_filename; $file_name = date('Y-m-d-his').'-'.$fixed_filename;
$import->file_path = $file_name; $import->file_path = $file_name;
$import->filesize = null;
if (!file_exists($path.'/'.$file_name)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 500);
}
$import->filesize = filesize($path.'/'.$file_name); $import->filesize = filesize($path.'/'.$file_name);
$import->save(); $import->save();
$results[] = $import; $results[] = $import;
} }

View file

@ -271,7 +271,7 @@ class SettingsController extends Controller
$headers = ['ContentType' => 'application/zip']; $headers = ['ContentType' => 'application/zip'];
return Storage::download($path.'/'.$file, $file, $headers); return Storage::download($path.'/'.$file, $file, $headers);
} else { } else {
return response()->json(Helper::formatStandardApiResponse('error', null, 'File not found')); return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')));
} }
} }

View file

@ -196,6 +196,7 @@ class StatuslabelsController extends Controller
{ {
$this->authorize('view', Statuslabel::class); $this->authorize('view', Statuslabel::class);
$statuslabels = Statuslabel::withCount('assets')->get(); $statuslabels = Statuslabel::withCount('assets')->get();
$total = Array();
foreach ($statuslabels as $statuslabel) { foreach ($statuslabels as $statuslabel) {

View file

@ -69,6 +69,7 @@ class UsersController extends Controller
'users.ldap_import', 'users.ldap_import',
'users.start_date', 'users.start_date',
'users.end_date', 'users.end_date',
'users.vip',
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',) ])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count'); ->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
@ -149,6 +150,10 @@ class UsersController extends Controller
$users = $users->where('remote', '=', $request->input('remote')); $users = $users->where('remote', '=', $request->input('remote'));
} }
if ($request->filled('vip')) {
$users = $users->where('vip', '=', $request->input('vip'));
}
if ($request->filled('two_factor_enrolled')) { if ($request->filled('two_factor_enrolled')) {
$users = $users->where('two_factor_enrolled', '=', $request->input('two_factor_enrolled')); $users = $users->where('two_factor_enrolled', '=', $request->input('two_factor_enrolled'));
} }

View file

@ -142,6 +142,7 @@ class AssetsController extends Controller
$asset->warranty_months = request('warranty_months', null); $asset->warranty_months = request('warranty_months', null);
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost')); $asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost'));
$asset->purchase_date = request('purchase_date', null); $asset->purchase_date = request('purchase_date', null);
$asset->asset_eol_date = request('asset_eol_date', null);
$asset->assigned_to = request('assigned_to', null); $asset->assigned_to = request('assigned_to', null);
$asset->supplier_id = request('supplier_id', null); $asset->supplier_id = request('supplier_id', null);
$asset->requestable = request('requestable', 0); $asset->requestable = request('requestable', 0);
@ -312,6 +313,8 @@ class AssetsController extends Controller
$asset->status_id = $request->input('status_id', null); $asset->status_id = $request->input('status_id', null);
$asset->warranty_months = $request->input('warranty_months', null); $asset->warranty_months = $request->input('warranty_months', null);
$asset->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null)); $asset->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null));
$asset->asset_eol_date = request('asset_eol_date', null);
$asset->purchase_date = $request->input('purchase_date', null); $asset->purchase_date = $request->input('purchase_date', null);
$asset->supplier_id = $request->input('supplier_id', null); $asset->supplier_id = $request->input('supplier_id', null);
$asset->expected_checkin = $request->input('expected_checkin', null); $asset->expected_checkin = $request->input('expected_checkin', null);

View file

@ -59,6 +59,12 @@ class LicenseCheckinController extends Controller
} }
$license = License::find($licenseSeat->license_id); $license = License::find($licenseSeat->license_id);
// LicenseSeat is not assigned, it can't be checked in
if (is_null($licenseSeat->assigned_to) && is_null($licenseSeat->asset_id)) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkin.error'));
}
$this->authorize('checkout', $license); $this->authorize('checkout', $license);
if (! $license->reassignable) { if (! $license->reassignable) {

View file

@ -227,6 +227,36 @@ class LocationsController extends Controller
} }
/**
* Returns a view that presents a form to clone a location.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $locationId
* @since [v6.0.14]
* @return View
*/
public function getClone($locationId = null)
{
$this->authorize('create', Location::class);
// Check if the asset exists
if (is_null($location_to_clone = Location::find($locationId))) {
// Redirect to the asset management page
return redirect()->route('licenses.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
$location = clone $location_to_clone;
// unset these values
$location->id = null;
$location->image = null;
return view('locations/edit')
->with('item', $location);
}
public function print_all_assigned($id) public function print_all_assigned($id)
{ {
if ($location = Location::where('id', $id)->first()) { if ($location = Location::where('id', $id)->first()) {

View file

@ -284,7 +284,7 @@ class ReportsController extends Controller
$row = [ $row = [
$actionlog->created_at, $actionlog->created_at,
($actionlog->user) ? e($actionlog->user->getFullNameAttribute()) : '', ($actionlog->admin) ? e($actionlog->admin->getFullNameAttribute()) : '',
$actionlog->present()->actionType(), $actionlog->present()->actionType(),
e($actionlog->itemType()), e($actionlog->itemType()),
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name, ($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,

View file

@ -65,18 +65,27 @@ class SettingsController extends Controller
$start_settings['db_error'] = $e->getMessage(); $start_settings['db_error'] = $e->getMessage();
} }
$protocol = array_key_exists('HTTPS', $_SERVER) && ('on' == $_SERVER['HTTPS']) ? 'https://' : 'http://'; if (array_key_exists("HTTP_X_FORWARDED_PROTO", $_SERVER)) {
$protocol = $_SERVER["HTTP_X_FORWARDED_PROTO"] . "://";
} elseif (array_key_exists('HTTPS', $_SERVER) && ('on' == $_SERVER['HTTPS'])) {
$protocol = "https://";
} else {
$protocol = "http://";
}
$host = array_key_exists('SERVER_NAME', $_SERVER) ? $_SERVER['SERVER_NAME'] : null; if (array_key_exists("HTTP_X_FORWARDED_HOST", $_SERVER)) {
$port = array_key_exists('SERVER_PORT', $_SERVER) ? $_SERVER['SERVER_PORT'] : null; $host = $_SERVER["HTTP_X_FORWARDED_HOST"];
if (('http://' === $protocol && '80' != $port) || ('https://' === $protocol && '443' != $port)) { } else {
$host .= ':'.$port; $host = array_key_exists('SERVER_NAME', $_SERVER) ? $_SERVER['SERVER_NAME'] : null;
$port = array_key_exists('SERVER_PORT', $_SERVER) ? $_SERVER['SERVER_PORT'] : null;
if (('http://' === $protocol && '80' != $port) || ('https://' === $protocol && '443' != $port)) {
$host .= ':'.$port;
}
} }
$pageURL = $protocol.$host.$_SERVER['REQUEST_URI']; $pageURL = $protocol.$host.$_SERVER['REQUEST_URI'];
$start_settings['url_valid'] = (url('/').'/setup' === $pageURL); $start_settings['url_config'] = url('/').'/setup';
$start_settings['url_valid'] = ($start_settings['url_config'] === $pageURL);
$start_settings['url_config'] = url('/');
$start_settings['real_url'] = $pageURL; $start_settings['real_url'] = $pageURL;
$start_settings['php_version_min'] = true; $start_settings['php_version_min'] = true;
@ -111,17 +120,17 @@ class SettingsController extends Controller
$start_settings['prod'] = true; $start_settings['prod'] = true;
} }
$start_settings['owner'] = '';
if (function_exists('posix_getpwuid')) { // Probably Linux if (function_exists('posix_getpwuid')) { // Probably Linux
$owner = posix_getpwuid(fileowner($_SERVER['SCRIPT_FILENAME'])); $owner = posix_getpwuid(fileowner($_SERVER['SCRIPT_FILENAME']));
$start_settings['owner'] = $owner['name']; // This *should* be an array, but we've seen this return a bool in some chrooted environments
} else { // Windows if (is_array($owner)) {
// TODO: Is there a way of knowing if a windows user has elevated permissions $start_settings['owner'] = $owner['name'];
// This just gets the user name, which likely isn't 'root' }
// $start_settings['owner'] = getenv('USERNAME');
$start_settings['owner'] = '';
} }
if (('root' === $start_settings['owner']) || ('0' === $start_settings['owner'])) { if (($start_settings['owner'] === 'root') || ($start_settings['owner'] === '0')) {
$start_settings['owner_is_admin'] = true; $start_settings['owner_is_admin'] = true;
} else { } else {
$start_settings['owner_is_admin'] = false; $start_settings['owner_is_admin'] = false;

View file

@ -38,7 +38,8 @@ class AssetsTransformer
'byod' => ($asset->byod ? true : false), 'byod' => ($asset->byod ? true : false),
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null, 'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'eol' => ($asset->purchase_date != '') ? Helper::getFormattedDateObject($asset->present()->eol_date(), 'date') : null, 'eol' => ($asset->model->eol != '') ? $asset->model->eol : null,
'asset_eol_date' => ($asset->asset_eol_date != '') ? Helper::getFormattedDateObject($asset->asset_eol_date, 'date') : null,
'status_label' => ($asset->assetstatus) ? [ 'status_label' => ($asset->assetstatus) ? [
'id' => (int) $asset->assetstatus->id, 'id' => (int) $asset->assetstatus->id,
'name'=> e($asset->assetstatus->name), 'name'=> e($asset->assetstatus->name),

View file

@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Models\Location; use App\Models\Location;
use Gate; use Illuminate\Support\Facades\Gate;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
@ -63,6 +63,7 @@ class LocationsTransformer
$permissions_array['available_actions'] = [ $permissions_array['available_actions'] = [
'update' => Gate::allows('update', Location::class) ? true : false, 'update' => Gate::allows('update', Location::class) ? true : false,
'delete' => $location->isDeletable(), 'delete' => $location->isDeletable(),
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
]; ];
$array += $permissions_array; $array += $permissions_array;

View file

@ -36,6 +36,7 @@ class UsersTransformer
'name'=> e($user->manager->first_name).' '.e($user->manager->last_name), 'name'=> e($user->manager->first_name).' '.e($user->manager->last_name),
] : null, ] : null,
'jobtitle' => ($user->jobtitle) ? e($user->jobtitle) : null, 'jobtitle' => ($user->jobtitle) ? e($user->jobtitle) : null,
'vip' => ($user->vip == '1') ? true : false,
'phone' => ($user->phone) ? e($user->phone) : null, 'phone' => ($user->phone) ? e($user->phone) : null,
'website' => ($user->website) ? e($user->website) : null, 'website' => ($user->website) ? e($user->website) : null,
'address' => ($user->address) ? e($user->address) : null, 'address' => ($user->address) ? e($user->address) : null,

View file

@ -76,10 +76,12 @@ class AssetImporter extends ItemImporter
} }
$this->item['notes'] = $this->findCsvMatch($row, 'asset_notes'); $this->item['notes'] = $this->findCsvMatch($row, 'asset_notes');
$this->item['image'] = $this->findCsvMatch($row, 'image'); $this->item['image'] = $this->findCsvMatch($row, 'image');
$this->item['requestable'] = $this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable')); $this->item['requestable'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable')) == 1) ? '1' : 0;
$asset->requestable = $this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable')); $asset->requestable = $this->item['requestable'];
$this->item['warranty_months'] = intval($this->findCsvMatch($row, 'warranty_months')); $this->item['warranty_months'] = intval($this->findCsvMatch($row, 'warranty_months'));
$this->item['model_id'] = $this->createOrFetchAssetModel($row); $this->item['model_id'] = $this->createOrFetchAssetModel($row);
$this->item['byod'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'byod')) == 1) ? '1' : 0;
// If no status ID is found // If no status ID is found
if (! array_key_exists('status_id', $this->item) && ! $editingAsset) { if (! array_key_exists('status_id', $this->item) && ! $editingAsset) {
@ -135,7 +137,7 @@ class AssetImporter extends ItemImporter
//-- user_id is a property of the abstract class Importer, which this class inherits from and it's setted by //-- user_id is a property of the abstract class Importer, which this class inherits from and it's setted by
//-- the class that needs to use it (command importer or GUI importer inside the project). //-- the class that needs to use it (command importer or GUI importer inside the project).
if (isset($target)) { if (isset($target)) {
$asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s')); $asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s'), null, $asset->notes, $asset->name);
} }
return; return;

View file

@ -58,6 +58,8 @@ class UserImporter extends ItemImporter
$this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department')); $this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department'));
$this->item['manager_id'] = $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name')); $this->item['manager_id'] = $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name'));
$this->item['remote'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'remote')) ==1 ) ? '1' : 0; $this->item['remote'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'remote')) ==1 ) ? '1' : 0;
$this->item['vip'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'vip')) ==1 ) ? '1' : 0;
$user_department = $this->findCsvMatch($row, 'department'); $user_department = $this->findCsvMatch($row, 'department');
if ($this->shouldUpdateField($user_department)) { if ($this->shouldUpdateField($user_department)) {

View file

@ -36,8 +36,10 @@
| name | | | | name | | |
| email | | | | email | | |
| username | | | | username | | |
| address | address | User | | address | address | User |
| city | city | User | | city | city | User |
| state | state | User | | state | state | User |
| country | country | User | | country | country | User |
| vip | vip | User |
| byod | byod | Asset |

View file

@ -114,6 +114,7 @@ class Asset extends Depreciable
'serial' => 'unique_serial|nullable', 'serial' => 'unique_serial|nullable',
'purchase_cost' => 'numeric|nullable|gte:0', 'purchase_cost' => 'numeric|nullable|gte:0',
'supplier_id' => 'exists:suppliers,id|nullable', 'supplier_id' => 'exists:suppliers,id|nullable',
'asset_eol_date' => 'date|max:10|min:10|nullable',
]; ];
/** /**
@ -143,9 +144,9 @@ class Asset extends Depreciable
'last_checkout', 'last_checkout',
'expected_checkin', 'expected_checkin',
'byod', 'byod',
'asset_eol_date',
'last_audit_date', 'last_audit_date',
'next_audit_date', 'next_audit_date',
]; ];
use Searchable; use Searchable;
@ -168,6 +169,7 @@ class Asset extends Depreciable
'expected_checkin', 'expected_checkin',
'next_audit_date', 'next_audit_date',
'last_audit_date', 'last_audit_date',
'asset_eol_date',
]; ];
/** /**
@ -181,7 +183,7 @@ class Asset extends Depreciable
'company' => ['name'], 'company' => ['name'],
'defaultLoc' => ['name'], 'defaultLoc' => ['name'],
'location' => ['name'], 'location' => ['name'],
'model' => ['name', 'model_number'], 'model' => ['name', 'model_number', 'eol'],
'model.category' => ['name'], 'model.category' => ['name'],
'model.manufacturer' => ['name'], 'model.manufacturer' => ['name'],
]; ];
@ -545,6 +547,28 @@ class Asset extends Depreciable
return strtolower(class_basename($this->assigned_type)); return strtolower(class_basename($this->assigned_type));
} }
/**
* This is annoying, but because we don't say "assets" in our route names, we have to make an exception here
* @todo - normalize the route names - API endpoint URLS can stay the same
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.1.0]
* @return string
*/
public function targetShowRoute()
{
$route = str_plural($this->assignedType());
if ($route=='assets') {
return 'hardware';
}
return $route;
}
/** /**
* Get the asset's location based on default RTD location * Get the asset's location based on default RTD location
* *

View file

@ -25,7 +25,10 @@ class CheckoutAcceptance extends Model
{ {
// At this point the endpoint is the same for everything. // At this point the endpoint is the same for everything.
// In the future this may want to be adapted for individual notifications. // In the future this may want to be adapted for individual notifications.
return Setting::getSettings()->alert_email; $recipients_string = explode(',', Setting::getSettings()->alert_email);
$recipients = array_map('trim', $recipients_string);
return array_filter($recipients);
} }
/** /**

View file

@ -16,7 +16,7 @@ class Depreciation extends SnipeModel
// Declare the rules for the form validation // Declare the rules for the form validation
protected $rules = [ protected $rules = [
'name' => 'required|min:3|max:255|unique:depreciations,name', 'name' => 'required|min:3|max:255|unique:depreciations,name',
'months' => 'required|max:3600|integer', 'months' => 'required|max:3600|integer|gt:0',
]; ];
/** /**

View file

@ -93,8 +93,12 @@ trait Loggable
{ {
$settings = Setting::getSettings(); $settings = Setting::getSettings();
$log = new Actionlog; $log = new Actionlog;
$log->target_type = get_class($target);
$log->target_id = $target->id; if($target != null){
$log->target_type = get_class($target);
$log->target_id = $target->id;
}
if (static::class == LicenseSeat::class) { if (static::class == LicenseSeat::class) {
$log->item_type = License::class; $log->item_type = License::class;

View file

@ -80,8 +80,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'created_at', 'created_at',
'updated_at', 'updated_at',
'deleted_at', 'deleted_at',
'start_date', 'start_date' => 'date_format:Y-m-d',
'end_date', 'end_date' => 'date_format:Y-m-d',
]; ];

View file

@ -163,9 +163,16 @@ class AssetPresenter extends Presenter
], [ ], [
'field' => 'eol', 'field' => 'eol',
'searchable' => false, 'searchable' => false,
'sortable' => false, 'sortable' => true,
'visible' => false, 'visible' => false,
'title' => trans('general.eol'), 'title' => trans('general.eol'),
],
[
'field' => 'asset_eol_date',
'searchable' => true,
'sortable' => true,
'visible' => false,
'title' => trans('admin/hardware/form.eol_date'),
'formatter' => 'dateDisplayFormatter', 'formatter' => 'dateDisplayFormatter',
], [ ], [
'field' => 'warranty_months', 'field' => 'warranty_months',

View file

@ -117,6 +117,11 @@ $config = [
\Log::info("IGNORING E_WARNING in production mode: ".$args->getMessage()); \Log::info("IGNORING E_WARNING in production mode: ".$args->getMessage());
return true; // "TRUE - you should ignore it!" return true; // "TRUE - you should ignore it!"
} }
$needle = "ArieTimmerman\\Laravel\\SCIMServer\\Exceptions\\SCIMException";
if (App::environment('production') && is_string($args) && strncmp($args, $needle, strlen($needle) ) === 0 ) {
\Log::info("String: '$args' looks like a SCIM Exception; ignoring error");
return true; //yes, *do* ignore it
}
return false; return false;
}, },
], ],

View file

@ -1,10 +1,10 @@
<?php <?php
return array ( return array (
'app_version' => 'v6.0.14', 'app_version' => 'v6.0.14',
'full_app_version' => 'v6.0.14 - build 9599-g1415c8c6e', 'full_app_version' => 'v6.0.14 - build 9646-g417a1e624',
'build_version' => '9599', 'build_version' => '9646',
'prerelease_version' => '', 'prerelease_version' => '',
'hash_version' => 'g1415c8c6e', 'hash_version' => 'g417a1e624',
'full_hash' => 'v6.0.14-555-g1415c8c6e', 'full_hash' => 'v6.0.14-602-g417a1e624',
'branch' => 'develop', 'branch' => 'develop',
); );

View file

@ -55,7 +55,7 @@ class ActionlogFactory extends Factory
[ [
'assigned_to' => $target->id, 'assigned_to' => $target->id,
'assigned_type' => \App\Models\User::class, 'assigned_type' => \App\Models\User::class,
'assigned_to' => $target->location_id, 'location_id' => $target->location_id,
] ]
); );
@ -84,7 +84,7 @@ class ActionlogFactory extends Factory
[ [
'assigned_to' => $target->id, 'assigned_to' => $target->id,
'assigned_type' => \App\Models\Location::class, 'assigned_type' => \App\Models\Location::class,
'assigned_to' => $target->id, 'location_id' => $target->id,
] ]
); );

View file

@ -46,7 +46,7 @@ class LicenseFactory extends Factory
'serial' => $this->faker->uuid, 'serial' => $this->faker->uuid,
'notes' => 'Created by DB seeder', 'notes' => 'Created by DB seeder',
'seats' => $this->faker->numberBetween(1, 10), 'seats' => $this->faker->numberBetween(1, 10),
'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()), 'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get())->format('Y-m-d'),
'order_number' => $this->faker->numberBetween(1000000, 50000000), 'order_number' => $this->faker->numberBetween(1000000, 50000000),
'expiration_date' => $this->faker->dateTimeBetween('now', '+3 years', date_default_timezone_get())->format('Y-m-d H:i:s'), 'expiration_date' => $this->faker->dateTimeBetween('now', '+3 years', date_default_timezone_get())->format('Y-m-d H:i:s'),
'reassignable' => $this->faker->boolean(), 'reassignable' => $this->faker->boolean(),

View file

@ -0,0 +1,54 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\Asset;
use App\Models\AssetModel;
class AddEolDateOnAssetsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('assets', function (Blueprint $table) {
if (!Schema::hasColumn('assets', 'asset_eol_date')) {
$table->date('asset_eol_date')->after('purchase_date')->nullable()->default(null);
}
});
// Chunk the model query to get the models that do have an EOL date
AssetModel::whereNotNull('eol')->with('assets')->chunk(200, function ($models) {
foreach ($models as $model) {
foreach ($model->assets as $asset) {
if ($asset->purchase_date!='') {
$asset->asset_eol_date = $asset->present()->eol_date();
$asset->save();
}
}
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('assets', function (Blueprint $table) {
if (Schema::hasColumn('assets', 'asset_eol_date')) {
$table->dropColumn('asset_eol_date');
}
});
}
}

6
package-lock.json generated
View file

@ -1329,9 +1329,9 @@
"dev": true "dev": true
}, },
"@fortawesome/fontawesome-free": { "@fortawesome/fontawesome-free": {
"version": "6.2.1", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.1.tgz", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.3.0.tgz",
"integrity": "sha512-viouXhegu/TjkvYQoiRZK3aax69dGXxgEjpvZW81wIJdxm5Fnvp3VVIP4VHKqX4SvFw6qpmkILkD4RJWAdrt7A==" "integrity": "sha512-qVtd5i1Cc7cdrqnTWqTObKQHjPWAiRwjUPaXObaeNPcy7+WKxJumGBx66rfSFgK6LNpIasVKkEgW8oyf0tmPLA=="
}, },
"@jridgewell/gen-mapping": { "@jridgewell/gen-mapping": {
"version": "0.1.1", "version": "0.1.1",

View file

@ -24,7 +24,7 @@
"vue-template-compiler": "2.4.4" "vue-template-compiler": "2.4.4"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.2.1", "@fortawesome/fontawesome-free": "^6.3.0",
"acorn": "^8.8.2", "acorn": "^8.8.2",
"acorn-import-assertions": "^1.8.0", "acorn-import-assertions": "^1.8.0",
"admin-lte": "^2.4.18", "admin-lte": "^2.4.18",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/dist/all.js vendored

Binary file not shown.

View file

@ -1,8 +1,8 @@
{ {
"/js/build/app.js": "/js/build/app.js?id=f05cc05b9000ba73e1949bcf137d4301", "/js/build/app.js": "/js/build/app.js?id=790387868822daaa28dcc3722928b7b1",
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=f677207c6cf9678eb539abecb408c374", "/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=f677207c6cf9678eb539abecb408c374",
"/css/build/overrides.css": "/css/build/overrides.css?id=0465141b9ecb0662ba6790c1460f391f", "/css/build/overrides.css": "/css/build/overrides.css?id=d9175e3d9b9074397343dddebfe23888",
"/css/build/app.css": "/css/build/app.css?id=c3a896cab26e2093f8be24336b7db1b9", "/css/build/app.css": "/css/build/app.css?id=dcb8aa9f4501a370214a67442e88daf0",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=dc383f8560a8d4adb51d44fb4043e03b", "/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=dc383f8560a8d4adb51d44fb4043e03b",
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=6f0563e726c2fe4fab4026daaa5bfdf2", "/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=6f0563e726c2fe4fab4026daaa5bfdf2",
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=f343f659ca1d45534d2c2c3cc30fb619", "/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=f343f659ca1d45534d2c2c3cc30fb619",
@ -18,23 +18,23 @@
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=0a82a6ae6bb4e58fe62d162c4fb50397", "/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=da6c7997d9de2f8329142399f0ce50da", "/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=da6c7997d9de2f8329142399f0ce50da",
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=44bf834f2110504a793dadec132a5898", "/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=44bf834f2110504a793dadec132a5898",
"/css/dist/all.css": "/css/dist/all.css?id=ef030b613d45620b907cf0184a14e868", "/css/dist/all.css": "/css/dist/all.css?id=0314c741a636de602ec952468eb171f3",
"/css/blue.png": "/css/blue.png?id=e83a6c29e04fe851f2122815b2e4b150", "/css/blue.png": "/css/blue.png?id=e83a6c29e04fe851f2122815b2e4b150",
"/css/blue@2x.png": "/css/blue@2x.png?id=51135dd4d24f88f5de0b2414bd51dac5", "/css/blue@2x.png": "/css/blue@2x.png?id=51135dd4d24f88f5de0b2414bd51dac5",
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7", "/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7", "/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=0b834d6c0ecc5bf275a83414eb38efd4", "/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=2df05d4beaa48550d71234e8dca79141",
"/css/webfonts/fa-brands-400.woff2": "/css/webfonts/fa-brands-400.woff2?id=a46924ee2a2a7702ef7fe7ead62fca18", "/css/webfonts/fa-brands-400.woff2": "/css/webfonts/fa-brands-400.woff2?id=682885a4f72597322017a9fcd0683831",
"/css/webfonts/fa-regular-400.ttf": "/css/webfonts/fa-regular-400.ttf?id=93d1ca4fec25c46c9ac67b07058b3f72", "/css/webfonts/fa-regular-400.ttf": "/css/webfonts/fa-regular-400.ttf?id=e7a7f9dd9376f68614860d920255d4df",
"/css/webfonts/fa-regular-400.woff2": "/css/webfonts/fa-regular-400.woff2?id=d8373194363409c201ee33fcd48ba574", "/css/webfonts/fa-regular-400.woff2": "/css/webfonts/fa-regular-400.woff2?id=204fc700c679395e6aa9bebc3cada64e",
"/css/webfonts/fa-solid-900.ttf": "/css/webfonts/fa-solid-900.ttf?id=a7d60e1f645d1b80e0879b2c8e72ed06", "/css/webfonts/fa-solid-900.ttf": "/css/webfonts/fa-solid-900.ttf?id=c9d3294ec75b843a31ef711069a0f0b6",
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=3e1cccc95e0dadb2168d67c2f0f23bf3", "/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=6707d0247b0bca1b4964bab435e3c0d6",
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=ee335846f3552dc6af2ef7c8cafae1dc", "/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=a947172f4fde88e43b4c1a60b01db061",
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=1ad361f755ce9c96dadb8da2d7318975", "/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=bbc23038a6067c78310d3f19432a3ebf",
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=ee4896df8b8f008ce73a9a0c2549aefd", "/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=ee4896df8b8f008ce73a9a0c2549aefd",
"/js/build/vendor.js": "/js/build/vendor.js?id=47ecbb4bb3b0e02315f391caadbdf971", "/js/build/vendor.js": "/js/build/vendor.js?id=47ecbb4bb3b0e02315f391caadbdf971",
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=14d9a2affec7b066d20fcba2e6e67ad2", "/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=14d9a2affec7b066d20fcba2e6e67ad2",
"/js/dist/all.js": "/js/dist/all.js?id=4f9355ac85d380301f6f62e55b1a6e5e", "/js/dist/all.js": "/js/dist/all.js?id=93f3ed97355821b50ee5bbd4f658dd05",
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=0a82a6ae6bb4e58fe62d162c4fb50397", "/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=c0d21166315b7c2cdd4819fa4a5e4d1e", "/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=c0d21166315b7c2cdd4819fa4a5e4d1e",
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=76482123f6c70e866d6b971ba91de7bb", "/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=76482123f6c70e866d6b971ba91de7bb",

View file

@ -671,18 +671,18 @@ th.css-accessory > .th-inner::before
} }
@media screen and (max-width: 511px){ @media screen and (max-width: 511px){
.sidebar-menu{ .sidebar-menu{
margin-top:64px; margin-top:160px;
} }
} }
@media screen and (max-width: 771px) and (min-width: 512px){ @media screen and (max-width: 771px) and (min-width: 512px){
.sidebar-menu { .sidebar-menu {
margin-top:14px margin-top:160px
} }
} }
@media screen and (max-width: 1098px) and (min-width: 772px){ @media screen and (max-width: 1098px) and (min-width: 772px){
.sidebar-menu { .sidebar-menu {
margin-top:51px margin-top:98px
} }
} }

View file

@ -395,7 +395,7 @@ return [
'end_date' => 'Enddatum', 'end_date' => 'Enddatum',
'alt_uploaded_image_thumbnail' => 'Hochgeladene Miniaturansicht', 'alt_uploaded_image_thumbnail' => 'Hochgeladene Miniaturansicht',
'placeholder_kit' => 'Kit auswählen', 'placeholder_kit' => 'Kit auswählen',
'file_not_found' => 'File not found', 'file_not_found' => 'File not found on server',
'preview_not_available' => '(no preview)', 'preview_not_available' => '(no preview)',
'setup' => 'Setup', 'setup' => 'Setup',
'pre_flight' => 'Pre-Flight', 'pre_flight' => 'Pre-Flight',

View file

@ -403,6 +403,8 @@ return [
'toggle_navigation' => 'Toggle navigation', 'toggle_navigation' => 'Toggle navigation',
'alerts' => 'Alerts', 'alerts' => 'Alerts',
'tasks_view_all' => 'View all tasks', 'tasks_view_all' => 'View all tasks',
'true' => 'True',
'false' => 'False',

View file

@ -41,7 +41,7 @@
<thead> <thead>
<tr> <tr>
<th data-switchable="true" data-sortable="false" data-field="id" data-visible="false">{{ trans('general.id') }}</th> <th data-switchable="true" data-sortable="true" data-field="id" data-visible="false">{{ trans('general.id') }}</th>
<th data-switchable="true" data-sortable="true" data-field="name" data-formatter="groupsAdminLinkFormatter" data-visible="true">{{ trans('admin/groups/table.name') }}</th> <th data-switchable="true" data-sortable="true" data-field="name" data-formatter="groupsAdminLinkFormatter" data-visible="true">{{ trans('admin/groups/table.name') }}</th>
<th data-switchable="true" data-sortable="true" data-field="users_count" data-visible="true">{{ trans('admin/groups/table.users') }}</th> <th data-switchable="true" data-sortable="true" data-field="users_count" data-visible="true">{{ trans('admin/groups/table.users') }}</th>
<th data-switchable="true" data-sortable="true" data-field="created_at" data-visible="true" data-formatter="dateDisplayFormatter">{{ trans('general.created_at') }}</th> <th data-switchable="true" data-sortable="true" data-field="created_at" data-visible="true" data-formatter="dateDisplayFormatter">{{ trans('general.created_at') }}</th>

View file

@ -152,6 +152,7 @@
<br> <br>
@include ('partials.forms.edit.order_number') @include ('partials.forms.edit.order_number')
@include ('partials.forms.edit.purchase_date') @include ('partials.forms.edit.purchase_date')
@include ('partials.forms.edit.eol_date')
@include ('partials.forms.edit.supplier-select', ['translated_name' => trans('general.supplier'), 'fieldname' => 'supplier_id']) @include ('partials.forms.edit.supplier-select', ['translated_name' => trans('general.supplier'), 'fieldname' => 'supplier_id'])
@php @php

View file

@ -673,7 +673,8 @@
</div> </div>
</div> </div>
@endif
@if ($asset->asset_eol_date)
<div class="row"> <div class="row">
<div class="col-md-2"> <div class="col-md-2">
<strong> <strong>
@ -681,10 +682,10 @@
</strong> </strong>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
@if ($asset->purchase_date) @if ($asset->asset_eol_date)
{{ Helper::getFormattedDateObject($asset->present()->eol_date(), 'date', false) }} {{ Helper::getFormattedDateObject($asset->asset_eol_date, 'date', false) }}
- -
{{ Carbon::parse($asset->present()->eol_date())->diffForHumans(['parts' => 2]) }} {{ Carbon::parse($asset->asset_eol_date)->diffForHumans(['parts' => 2]) }}
@else @else
{{ trans('general.na_no_purchase_date') }} {{ trans('general.na_no_purchase_date') }}
@endif @endif

View file

@ -65,50 +65,3 @@
@include ('partials.forms.edit.image-upload') @include ('partials.forms.edit.image-upload')
@stop @stop
@if (!$item->id)
@section('moar_scripts')
<script nonce="{{ csrf_token() }}">
var $eventSelect = $(".parent");
$eventSelect.on("change", function () { parent_details($eventSelect.val()); });
$(function() {
var parent_loc = $(".parent option:selected").val();
if(parent_loc!=''){
parent_details(parent_loc);
}
});
function parent_details(id) {
if (id) {
//start ajax request
$.ajax({
type: 'GET',
url: "{{url('/') }}/api/locations/"+id+"/check",
//force to handle it as text
dataType: "text",
success: function(data) {
var json = $.parseJSON(data);
$("#city").val(json.city);
$("#address").val(json.address);
$("#address2").val(json.address2);
$("#state").val(json.state);
$("#zip").val(json.zip);
$(".country").select2("val",json.country);
}
});
} else {
$("#city").val('');
$("#address").val('');
$("#address2").val('');
$("#state").val('');
$("#zip").val('');
$(".country").select2("val",'');
}
};
</script>
@stop
@endif

View file

@ -10,7 +10,7 @@
@php @php
$checkin = Helper::getFormattedDateObject($asset->expected_checkin, 'date'); $checkin = Helper::getFormattedDateObject($asset->expected_checkin, 'date');
@endphp @endphp
| [{{ $asset->present()->name }}]({{ route('hardware.show', ['hardware' => $asset->id]) }}) | [{{ $asset->assigned->present()->fullName }}]({{ route('users.show', ['user'=>$asset->assigned->id]) }}) | {{ $checkin['formatted'] }} | [{{ $asset->present()->name }}]({{ route('hardware.show', ['hardware' => $asset->id]) }}) | [{{ $asset->assigned->present()->fullName }}]({{ route($asset->targetShowRoute().'.show', [$asset->assigned->id]) }}) | {{ $checkin['formatted'] }}
@endforeach @endforeach
@endcomponent @endcomponent

View file

@ -570,9 +570,9 @@
function trueFalseFormatter(value) { function trueFalseFormatter(value) {
if ((value) && ((value == 'true') || (value == '1'))) { if ((value) && ((value == 'true') || (value == '1'))) {
return '<i class="fas fa-check text-success"></i>'; return '<i class="fas fa-check text-success"></i><span class="sr-only">{{ trans('general.true') }}</span>';
} else { } else {
return '<i class="fas fa-times text-danger"></i>'; return '<i class="fas fa-times text-danger"></i><span class="sr-only">{{ trans('general.false') }}</span>';
} }
} }

View file

@ -3,7 +3,7 @@
{{ Form::label($fieldname, $translated_name, array('class' => 'col-md-3 control-label')) }} {{ Form::label($fieldname, $translated_name, array('class' => 'col-md-3 control-label')) }}
<div class="input-group col-md-4"> <div class="input-group col-md-4">
<div class="input-group date" data-provide="datepicker" data-date-clear-btn="true" data-date-format="yyyy-mm-dd" data-autoclose="true"> <div class="input-group date" data-provide="datepicker" data-date-clear-btn="true" data-date-format="yyyy-mm-dd" data-autoclose="true">
<input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="{{ $fieldname }}" id="{{ $fieldname }}" value="{{ old($fieldname, ($item->{$fieldname}) ? $item->{$fieldname}->format('Y-m-d') : '') }}" readonly style="background-color:inherit"> <input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="{{ $fieldname }}" id="{{ $fieldname }}" value="{{ old($fieldname, ($item->{$fieldname}) ? date('Y-m-d', strtotime($item->{$fieldname})) : '') }}" readonly style="background-color:inherit">
<span class="input-group-addon"><i class="fas fa-calendar" aria-hidden="true"></i></span> <span class="input-group-addon"><i class="fas fa-calendar" aria-hidden="true"></i></span>
</div> </div>
{!! $errors->first($fieldname, '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!} {!! $errors->first($fieldname, '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}

View file

@ -0,0 +1,11 @@
<!-- Purchase Date -->
<div class="form-group {{ $errors->has('asset_eol_date') ? ' has-error' : '' }}">
<label for="asset_eol_date" class="col-md-3 control-label">{{ trans('admin/hardware/form.eol_date') }}</label>
<div class="input-group col-md-4">
<div class="input-group date" data-provide="datepicker" data-date-clear-btn="true" data-date-format="yyyy-mm-dd" data-autoclose="true">
<input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="asset_eol_date" id="asset_eol_date" readonly value="{{ old('asset_eol_date', $item->asset_eol_date ?? $item->present()->eol_date() ?? '') }}" style="background-color:inherit">
<span class="input-group-addon"><i class="fas fa-calendar" aria-hidden="true"></i></span>
</div>
{!! $errors->first('asset_eol_date', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
</div>

View file

@ -35,7 +35,7 @@
<thead> <thead>
<tr> <tr>
<th class="col-sm-1" data-field="company">{{ trans('admin/companies/table.title') }}</th> <th class="col-sm-1" data-field="company.name">{{ trans('admin/companies/table.title') }}</th>
<th class="col-sm-1" data-field="name">{{ trans('admin/accessories/table.title') }}</th> <th class="col-sm-1" data-field="name">{{ trans('admin/accessories/table.title') }}</th>
<th class="col-sm-1" data-field="model_number">{{ trans('general.model_no') }}</th> <th class="col-sm-1" data-field="model_number">{{ trans('general.model_no') }}</th>
<th class="col-sm-1" data-field="qty">{{ trans('admin/accessories/general.total') }}</th> <th class="col-sm-1" data-field="qty">{{ trans('admin/accessories/general.total') }}</th>

View file

@ -40,22 +40,36 @@ Route::group(['middleware' => 'auth'], function () {
'parameters' => ['category' => 'category_id'], 'parameters' => ['category' => 'category_id'],
]); ]);
/* /*
* Locations * Locations
*/ */
Route::group(['prefix' => 'locations', 'middleware' => ['auth']], function () {
Route::get('{locationId}/clone',
[LocationsController::class, 'getClone']
)->name('clone/license');
Route::get(
'{locationId}/printassigned',
[LocationsController::class, 'print_assigned']
)->name('locations.print_assigned');
Route::get(
'{locationId}/printallassigned',
[LocationsController::class, 'print_all_assigned']
)->name('locations.print_all_assigned');
});
Route::resource('locations', LocationsController::class, [ Route::resource('locations', LocationsController::class, [
'parameters' => ['location' => 'location_id'], 'parameters' => ['location' => 'location_id'],
]); ]);
Route::get(
'locations/{locationId}/printassigned',
[LocationsController::class, 'print_assigned']
)->name('locations.print_assigned');
Route::get(
'locations/{locationId}/printallassigned',
[LocationsController::class, 'print_all_assigned']
)->name('locations.print_all_assigned');
/* /*
* Manufacturers * Manufacturers

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff