Merge branch 'develop' into snipeit_v7_laravel10

This commit is contained in:
Brady Wetherington 2023-09-07 20:11:41 +01:00
commit ec1059e74c
39 changed files with 505 additions and 600 deletions

View file

@ -6,7 +6,6 @@ environment:
services:
- mysql: 5.7
- dusk:
on:
push:
@ -43,19 +42,3 @@ pipeline:
- name: PHPUnit Feature Tests
cmd: |
php artisan test --testsuite Feature
# - name: Browser Tests
# cmd: |
# cp -v .env.dusk.example .env.dusk.ci
# sed -i "s@APP_ENV=.*@APP_ENV=ci@g" .env.dusk.ci
# sed -i "s@APP_URL=.*@APP_URL=http://$BUILD_HOST:8000@g" .env.dusk.ci
# #sed -i "s@DB_HOST=.*@DB_HOST=mysql@g" .env.dusk.ci
# sed -i "s@DB_HOST=.*@DB_HOST=$DB_HOST@g" .env.dusk.ci
# sed -i "s@DB_USERNAME=.*@DB_USERNAME=chipperci@g" .env.dusk.ci
# sed -i "s@DB_DATABASE=.*@DB_DATABASE=chipperci@g" .env.dusk.ci
# sed -i "s@DB_PASSWORD=.*@DB_PASSWORD=secret@g" .env.dusk.ci
#
# php -S [::0]:8000 -t public 2>server.log &
# sleep 2
# php artisan dusk:chrome-driver $CHROME_DRIVER
# php artisan dusk --env=ci

2
.gitignore vendored
View file

@ -1,8 +1,6 @@
.couscous
.DS_Store
.env
.env.dusk.*
!.env.dusk.example
.env.testing
phpstan.neon
.idea

View file

@ -9,7 +9,39 @@ Before starting, follow the [instructions](README.md#installation) for installin
Before attempting to run the test suite copy the example environment file for tests and update the values to match your environment:
`cp .env.testing.example .env.testing`
> Since the data in the database is flushed after each test it is recommended you create a separate mysql database for specifically for tests
The following should work for running tests in memory with sqlite:
```
# --------------------------------------------
# REQUIRED: BASIC APP SETTINGS
# --------------------------------------------
APP_ENV=testing
APP_DEBUG=true
APP_KEY=base64:glJpcM7BYwWiBggp3SQ/+NlRkqsBQMaGEOjemXqJzOU=
APP_URL=http://localhost:8000
APP_TIMEZONE='UTC'
APP_LOCALE=en
# --------------------------------------------
# REQUIRED: DATABASE SETTINGS
# --------------------------------------------
DB_CONNECTION=sqlite_testing
#DB_HOST=127.0.0.1
#DB_PORT=3306
#DB_DATABASE=null
#DB_USERNAME=null
#DB_PASSWORD=null
```
To use MySQL you should update the `DB_` variables to match your local test database:
```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE={}
DB_USERNAME={}
DB_PASSWORD={}
```
Now you are ready to run the entire test suite from your terminal:
@ -18,34 +50,3 @@ Now you are ready to run the entire test suite from your terminal:
To run individual test files, you can pass the path to the test that you want to run:
`php artisan test tests/Unit/AccessoryTest.php`
## Browser Tests
Browser tests are run via [Laravel Dusk](https://laravel.com/docs/8.x/dusk) and require Google Chrome to be installed.
Before attempting to run Dusk tests copy the example environment file for Dusk and update the values to match your environment:
`cp .env.dusk.example .env.dusk.local`
> `local` refers to the value of `APP_ENV` in your `.env` so if you have it set to `dev` then the file should be named `.env.dusk.dev`.
**Important**: Dusk tests cannot be run using an in-memory SQLite database. Additionally, the Dusk test suite uses the `DatabaseMigrations` trait which will leave the database in a fresh state after running. Therefore, it is recommended that you create a test database and point `DB_DATABASE` in `.env.dusk.local` to it.
### Running Browser Tests
Your application needs to be configured and up and running in order for the browser tests to actually run. When running the tests locally, you can start the application using the following command:
`php artisan serve`
Now you are ready to run the test suite. Use the following command from another terminal tab or window:
`php artisan dusk`
To run individual test files, you can pass the path to the test that you want to run:
`php artisan dusk tests/Browser/LoginTest.php`
If you get an error when attempting to run Dusk tests that says `Couldn't connect to server` run:
`php artisan dusk:chrome-driver --detect`
This command will install the specific ChromeDriver Dusk needs for your operating system and Chrome version.

View file

@ -15,18 +15,20 @@ class CheckoutableCheckedIn
public $checkedInBy;
public $note;
public $action_date; // Date setted in the hardware.checkin view at the checkin_at input, for the action log
public $originalValues;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($checkoutable, $checkedOutTo, User $checkedInBy, $note, $action_date = null)
public function __construct($checkoutable, $checkedOutTo, User $checkedInBy, $note, $action_date = null, $originalValues = [])
{
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
$this->checkedInBy = $checkedInBy;
$this->note = $note;
$this->action_date = $action_date ?? date('Y-m-d');
$this->originalValues = $originalValues;
}
}

View file

@ -14,17 +14,19 @@ class CheckoutableCheckedOut
public $checkedOutTo;
public $checkedOutBy;
public $note;
public $originalValues;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note)
public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note, $originalValues = [])
{
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
$this->checkedOutBy = $checkedOutBy;
$this->note = $note;
$this->originalValues = $originalValues;
}
}

View file

@ -905,6 +905,7 @@ class AssetsController extends Controller
$asset->expected_checkin = null;
$asset->last_checkout = null;
$asset->last_checkin = now();
$asset->assigned_to = null;
$asset->assignedTo()->disassociate($asset);
$asset->accepted = null;
@ -924,10 +925,14 @@ class AssetsController extends Controller
}
$checkin_at = $request->filled('checkin_at') ? $request->input('checkin_at').' '. date('H:i:s') : date('Y-m-d H:i:s');
$originalValues = $asset->getRawOriginal();
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
$originalValues['action_date'] = $checkin_at;
}
if ($asset->save()) {
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at));
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.success')));
}

View file

@ -68,6 +68,7 @@ class AssetCheckinController extends Controller
$asset->expected_checkin = null;
$asset->last_checkout = null;
$asset->last_checkin = now();
$asset->assigned_to = null;
$asset->assignedTo()->disassociate($asset);
$asset->assigned_type = null;
@ -108,8 +109,11 @@ class AssetCheckinController extends Controller
}
}
$originalValues = $asset->getRawOriginal();
$checkin_at = date('Y-m-d H:i:s');
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
$originalValues['action_date'] = $checkin_at;
$checkin_at = $request->get('checkin_at');
}
@ -132,7 +136,7 @@ class AssetCheckinController extends Controller
// Was the asset updated?
if ($asset->save()) {
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at));
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
if ((isset($user)) && ($backto == 'user')) {
return redirect()->route('users.show', $user->id)->with('success', trans('admin/hardware/message.checkin.success'));

View file

@ -58,8 +58,14 @@ class BulkAssetsController extends Controller
switch ($request->input('bulk_actions')) {
case 'labels':
$this->authorize('view', Asset::class);
$assets_found = Asset::find($asset_ids);
if ($assets_found->isEmpty()){
return redirect()->back();
}
return (new Label)
->with('assets', Asset::find($asset_ids))
->with('assets', $assets_found)
->with('settings', Setting::getSettings())
->with('bulkedit', true)
->with('count', 0);

View file

@ -545,6 +545,10 @@ class ReportsController extends Controller
$header[] = trans('admin/hardware/table.checkout_date');
}
if ($request->filled('checkin_date')) {
$header[] = trans('admin/hardware/table.last_checkin_date');
}
if ($request->filled('expected_checkin')) {
$header[] = trans('admin/hardware/form.expected_checkin');
}
@ -651,6 +655,14 @@ class ReportsController extends Controller
$assets->whereBetween('assets.last_checkout', [$checkout_start, $checkout_end]);
}
if (($request->filled('checkin_date_start'))) {
$assets->whereBetween('last_checkin', [
Carbon::parse($request->input('checkin_date_start'))->startOfDay(),
// use today's date is `checkin_date_end` is not provided
Carbon::parse($request->input('checkin_date_end', now()))->endOfDay(),
]);
}
if (($request->filled('expected_checkin_start')) && ($request->filled('expected_checkin_end'))) {
$assets->whereBetween('assets.expected_checkin', [$request->input('expected_checkin_start'), $request->input('expected_checkin_end')]);
}
@ -835,6 +847,12 @@ class ReportsController extends Controller
$row[] = ($asset->last_checkout) ? $asset->last_checkout : '';
}
if ($request->filled('checkin_date')) {
$row[] = ($asset->last_checkin)
? Carbon::parse($asset->last_checkin)->format('Y-m-d')
: '';
}
if ($request->filled('expected_checkin')) {
$row[] = ($asset->expected_checkin) ? $asset->expected_checkin : '';
}

View file

@ -3,6 +3,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Actionlog;
use App\Models\CustomField;
use App\Models\Setting;
use App\Models\Company;
use App\Models\Supplier;
@ -42,6 +43,7 @@ class ActionlogsTransformer
public function transformActionlog (Actionlog $actionlog, $settings = null)
{
$icon = $actionlog->present()->icon();
$custom_field = CustomField::all();
if ($actionlog->filename!='') {
$icon = e(\App\Helpers\Helper::filetype_icon($actionlog->filename));
}
@ -54,12 +56,20 @@ class ActionlogsTransformer
if ($meta_array) {
foreach ($meta_array as $fieldname => $fieldata) {
$clean_meta[$fieldname]['old'] = $this->clean_field($fieldata->old);
$clean_meta[$fieldname]['new'] = $this->clean_field($fieldata->new);
if( str_starts_with($fieldname, '_snipeit_')){
if( $custom_field->where('db_column', '=', $fieldname)->where('field_encrypted', true)){
$clean_meta[$fieldname]['old'] = "encrypted";
$clean_meta[$fieldname]['new'] = "encrypted";
}
}
else {
$clean_meta[$fieldname]['old'] = $this->clean_field($fieldata->old);
$clean_meta[$fieldname]['new'] = $this->clean_field($fieldata->new);
}
}
}
$clean_meta= $this->changedInfo($clean_meta);
$clean_meta = $this->changedInfo($clean_meta);
}
}
$file_url = '';
@ -123,6 +133,9 @@ class ActionlogsTransformer
'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
];
// \Log::info("Clean Meta is: ".print_r($clean_meta,true));
//dd($array);
return $array;
}
@ -143,39 +156,70 @@ class ActionlogsTransformer
* @param array $clean_meta
* @return array
*/
public function changedInfo(array $clean_meta)
{
{ $location = Location::withTrashed()->get();
$supplier = Supplier::withTrashed()->get();
$model = AssetModel::withTrashed()->get();
$company = Company::get();
if(array_key_exists('rtd_location_id',$clean_meta)) {
$clean_meta['rtd_location_id']['old'] = $clean_meta['rtd_location_id']['old'] ? "[id: ".$clean_meta['rtd_location_id']['old']."] ". Location::find($clean_meta['rtd_location_id']['old'])->name : trans('general.unassigned');
$clean_meta['rtd_location_id']['new'] = $clean_meta['rtd_location_id']['new'] ? "[id: ".$clean_meta['rtd_location_id']['new']."] ". Location::find($clean_meta['rtd_location_id']['new'])->name : trans('general.unassigned');
$clean_meta['rtd_location_id']['old'] = $clean_meta['rtd_location_id']['old'] ? "[id: ".$clean_meta['rtd_location_id']['old']."] ". $location->find($clean_meta['rtd_location_id']['old'])->name : trans('general.unassigned');
$clean_meta['rtd_location_id']['new'] = $clean_meta['rtd_location_id']['new'] ? "[id: ".$clean_meta['rtd_location_id']['new']."] ". $location->find($clean_meta['rtd_location_id']['new'])->name : trans('general.unassigned');
$clean_meta['Default Location'] = $clean_meta['rtd_location_id'];
unset($clean_meta['rtd_location_id']);
}
if(array_key_exists('location_id', $clean_meta)) {
$clean_meta['location_id']['old'] = $clean_meta['location_id']['old'] ? "[id: ".$clean_meta['location_id']['old']."] ".Location::find($clean_meta['location_id']['old'])->name : trans('general.unassigned');
$clean_meta['location_id']['new'] = $clean_meta['location_id']['new'] ? "[id: ".$clean_meta['location_id']['new']."] ".Location::find($clean_meta['location_id']['new'])->name : trans('general.unassigned');
$clean_meta['location_id']['old'] = $clean_meta['location_id']['old'] ? "[id: ".$clean_meta['location_id']['old']."] ".$location->find($clean_meta['location_id']['old'])->name : trans('general.unassigned');
$clean_meta['location_id']['new'] = $clean_meta['location_id']['new'] ? "[id: ".$clean_meta['location_id']['new']."] ".$location->find($clean_meta['location_id']['new'])->name : trans('general.unassigned');
$clean_meta['Current Location'] = $clean_meta['location_id'];
unset($clean_meta['location_id']);
}
if(array_key_exists('model_id', $clean_meta)) {
$clean_meta['model_id']['old'] = "[id: ".$clean_meta['model_id']['old']."] ".AssetModel::withTrashed()->find($clean_meta['model_id']['old'])->name;
$clean_meta['model_id']['new'] = "[id: ".$clean_meta['model_id']['new']."] ".AssetModel::withTrashed()->find($clean_meta['model_id']['new'])->name; /* model is required at asset creation */
$oldModel = $model->find($clean_meta['model_id']['old']);
$oldModelName = $oldModel->name ?? trans('admin/models/message.deleted');
$newModel = $model->find($clean_meta['model_id']['new']);
$newModelName = $newModel->name ?? trans('admin/models/message.deleted');
$clean_meta['model_id']['old'] = "[id: ".$clean_meta['model_id']['old']."] ".$oldModelName;
$clean_meta['model_id']['new'] = "[id: ".$clean_meta['model_id']['new']."] ".$newModelName; /** model is required at asset creation */
$clean_meta['Model'] = $clean_meta['model_id'];
unset($clean_meta['model_id']);
}
if(array_key_exists('company_id', $clean_meta)) {
$clean_meta['company_id']['old'] = $clean_meta['company_id']['old'] ? "[id: ".$clean_meta['company_id']['old']."]".Company::find($clean_meta['company_id']['old'])->name : trans('general.unassigned');
$clean_meta['company_id']['new'] = $clean_meta['company_id']['new'] ? "[id: ".$clean_meta['company_id']['new']."] ".Company::find($clean_meta['company_id']['new'])->name : trans('general.unassigned');
$oldCompany = $company->find($clean_meta['company_id']['old']);
$oldCompanyName = $oldCompany->name ?? trans('admin/companies/message.deleted');
$newCompany = $company->find($clean_meta['company_id']['new']);
$newCompanyName = $newCompany->name ?? trans('admin/companies/message.deleted');
$clean_meta['company_id']['old'] = $clean_meta['company_id']['old'] ? "[id: ".$clean_meta['company_id']['old']."] ". $oldCompanyName : trans('general.unassigned');
$clean_meta['company_id']['new'] = $clean_meta['company_id']['new'] ? "[id: ".$clean_meta['company_id']['new']."] ". $newCompanyName : trans('general.unassigned');
$clean_meta['Company'] = $clean_meta['company_id'];
unset($clean_meta['company_id']);
}
if(array_key_exists('supplier_id', $clean_meta)) {
$clean_meta['supplier_id']['old'] = $clean_meta['supplier_id']['old'] ? "[id: ".$clean_meta['supplier_id']['old']."] ".Supplier::find($clean_meta['supplier_id']['old'])->name : trans('general.unassigned');
$clean_meta['supplier_id']['new'] = $clean_meta['supplier_id']['new'] ? "[id: ".$clean_meta['supplier_id']['new']."] ".Supplier::find($clean_meta['supplier_id']['new'])->name : trans('general.unassigned');
$oldSupplier = $supplier->find($clean_meta['supplier_id']['old']);
$oldSupplierName = $oldSupplier->name ?? trans('admin/suppliers/message.deleted');
$newSupplier = $supplier->find($clean_meta['supplier_id']['new']);
$newSupplierName = $newSupplier->name ?? trans('admin/suppliers/message.deleted');
$clean_meta['supplier_id']['old'] = $clean_meta['supplier_id']['old'] ? "[id: ".$clean_meta['supplier_id']['old']."] ". $oldSupplierName : trans('general.unassigned');
$clean_meta['supplier_id']['new'] = $clean_meta['supplier_id']['new'] ? "[id: ".$clean_meta['supplier_id']['new']."] ". $newSupplierName : trans('general.unassigned');
$clean_meta['Supplier'] = $clean_meta['supplier_id'];
unset($clean_meta['supplier_id']);
}
if(array_key_exists('asset_eol_date', $clean_meta)) {
$clean_meta['EOL date'] = $clean_meta['asset_eol_date'];
unset($clean_meta['asset_eol_date']);
}
return $clean_meta;

View file

@ -33,7 +33,7 @@ class LogListener
*/
public function onCheckoutableCheckedIn(CheckoutableCheckedIn $event)
{
$event->checkoutable->logCheckin($event->checkedOutTo, $event->note, $event->action_date);
$event->checkoutable->logCheckin($event->checkedOutTo, $event->note, $event->action_date, $event->originalValues);
}
/**
@ -46,7 +46,7 @@ class LogListener
*/
public function onCheckoutableCheckedOut(CheckoutableCheckedOut $event)
{
$event->checkoutable->logCheckout($event->note, $event->checkedOutTo, $event->checkoutable->last_checkout);
$event->checkoutable->logCheckout($event->note, $event->checkedOutTo, $event->checkoutable->last_checkout, $event->originalValues);
}
/**

View file

@ -73,6 +73,7 @@ class Asset extends Depreciable
protected $casts = [
'purchase_date' => 'date',
'last_checkout' => 'datetime',
'last_checkin' => 'datetime',
'expected_checkin' => 'date',
'last_audit_date' => 'datetime',
'next_audit_date' => 'date',
@ -332,6 +333,13 @@ class Asset extends Depreciable
}
}
$originalValues = $this->getRawOriginal();
// attempt to detect change in value if different from today's date
if ($checkout_at && strpos($checkout_at, date('Y-m-d')) === false) {
$originalValues['action_date'] = date('Y-m-d H:i:s');
}
if ($this->save()) {
if (is_int($admin)) {
$checkedOutBy = User::findOrFail($admin);
@ -340,7 +348,7 @@ class Asset extends Depreciable
} else {
$checkedOutBy = Auth::user();
}
event(new CheckoutableCheckedOut($this, $target, $checkedOutBy, $note));
event(new CheckoutableCheckedOut($this, $target, $checkedOutBy, $note, $originalValues));
$this->increment('checkout_counter', 1);

View file

@ -323,7 +323,10 @@ class License extends Depreciable
*/
public function checkin_email()
{
return $this->category->checkin_email;
if ($this->category) {
return $this->category->checkin_email;
}
return false;
}
/**
@ -335,7 +338,11 @@ class License extends Depreciable
*/
public function requireAcceptance()
{
return $this->category->require_acceptance;
if ($this->category) {
return $this->category->require_acceptance;
}
return false;
}
/**
@ -348,14 +355,16 @@ class License extends Depreciable
*/
public function getEula()
{
if ($this->category->eula_text) {
return Helper::parseEscapedMarkedown($this->category->eula_text);
} elseif ($this->category->use_default_eula == '1') {
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
} else {
return false;
if ($this->category){
if ($this->category->eula_text) {
return Helper::parseEscapedMarkedown($this->category->eula_text);
} elseif ($this->category->use_default_eula == '1') {
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
}
}
return false;
}
/**

View file

@ -48,7 +48,10 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild
*/
public function requireAcceptance()
{
return $this->license->category->require_acceptance;
if ($this->license && $this->license->category) {
return $this->license->category->require_acceptance;
}
return false;
}
public function getEula()

View file

@ -23,7 +23,7 @@ trait Loggable
* @since [v3.4]
* @return \App\Models\Actionlog
*/
public function logCheckout($note, $target, $action_date = null)
public function logCheckout($note, $target, $action_date = null, $originalValues = [])
{
$log = new Actionlog;
$log = $this->determineLogItemType($log);
@ -62,6 +62,23 @@ trait Loggable
$log->action_date = date('Y-m-d H:i:s');
}
$changed = [];
$originalValues = array_intersect_key($originalValues, array_flip(['action_date','name','status_id','location_id','expected_checkin']));
foreach ($originalValues as $key => $value) {
if ($key == 'action_date' && $value != $action_date) {
$changed[$key]['old'] = $value;
$changed[$key]['new'] = is_string($action_date) ? $action_date : $action_date->format('Y-m-d H:i:s');
} elseif ($value != $this->getAttributes()[$key]) {
$changed[$key]['old'] = $value;
$changed[$key]['new'] = $this->getAttributes()[$key];
}
}
if (!empty($changed)){
$log->log_meta = json_encode($changed);
}
$log->logaction('checkout');
return $log;
@ -89,7 +106,7 @@ trait Loggable
* @since [v3.4]
* @return \App\Models\Actionlog
*/
public function logCheckin($target, $note, $action_date = null)
public function logCheckin($target, $note, $action_date = null, $originalValues = [])
{
$settings = Setting::getSettings();
$log = new Actionlog;
@ -114,13 +131,9 @@ trait Loggable
}
}
$log->location_id = null;
$log->note = $note;
$log->action_date = $action_date;
if (! $log->action_date) {
$log->action_date = date('Y-m-d H:i:s');
}
if (! $log->action_date) {
$log->action_date = date('Y-m-d H:i:s');
@ -130,6 +143,23 @@ trait Loggable
$log->user_id = Auth::user()->id;
}
$changed = [];
$originalValues = array_intersect_key($originalValues, array_flip(['action_date','name','status_id','location_id','rtd_location_id','expected_checkin']));
foreach ($originalValues as $key => $value) {
if ($key == 'action_date' && $value != $action_date) {
$changed[$key]['old'] = $value;
$changed[$key]['new'] = is_string($action_date) ? $action_date : $action_date->format('Y-m-d H:i:s');
} elseif ($value != $this->getAttributes()[$key]) {
$changed[$key]['old'] = $value;
$changed[$key]['new'] = $this->getAttributes()[$key];
}
}
if (!empty($changed)){
$log->log_meta = json_encode($changed);
}
$log->logaction('checkin from');
// $params = [

View file

@ -750,4 +750,26 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
{
return $this->locale;
}
public function getUserTotalCost(){
$asset_cost= 0;
$license_cost= 0;
$accessory_cost= 0;
foreach ($this->assets as $asset){
$asset_cost += $asset->purchase_cost;
$this->asset_cost = $asset_cost;
}
foreach ($this->licenses as $license){
$license_cost += $license->purchase_cost;
$this->license_cost = $license_cost;
}
foreach ($this->accessories as $accessory){
$accessory_cost += $accessory->purchase_cost;
$this->accessory_cost = $accessory_cost;
}
$this->total_user_cost = ($asset_cost + $accessory_cost + $license_cost);
return $this;
}
}

View file

@ -548,8 +548,10 @@ class AssetPresenter extends Presenter
public function dynamicWarrantyUrl()
{
$warranty_lookup_url = $this->model->model->manufacturer->warranty_lookup_url;
$url = (str_replace('{LOCALE}',\App\Models\Setting::getSettings()->locale,$warranty_lookup_url));
$url = (str_replace('{SERIAL}',$this->model->serial,$url));
$url = (str_replace('{LOCALE}',\App\Models\Setting::getSettings()->locale, $warranty_lookup_url));
$url = (str_replace('{SERIAL}', urlencode($this->model->serial), $url));
$url = (str_replace('{MODEL_NAME}', urlencode($this->model->model->name), $url));
$url = (str_replace('{MODEL_NUMBER}', urlencode($this->model->model->model_number), $url));
return $url;
}

View file

@ -75,12 +75,7 @@ class AppServiceProvider extends ServiceProvider
// Only load rollbar if there is a rollbar key and the app is in production
if (($this->app->environment('production')) && (config('logging.channels.rollbar.access_token'))) {
$this->app->register(\Rollbar\Laravel\RollbarServiceProvider::class);
}
// Only load dusk's service provider if the app is in local or develop mode
if ($this->app->environment(['local', 'develop'])) {
$this->app->register(\Laravel\Dusk\DuskServiceProvider::class);
}
}
$this->app->singleton('ArieTimmerman\Laravel\SCIMServer\SCIMConfig', SnipeSCIMConfig::class); // this overrides the default SCIM configuration with our own

View file

@ -64,7 +64,6 @@
"require-dev": {
"brianium/paratest": "^v6.4.4",
"fakerphp/faker": "^1.16",
"laravel/dusk": "^v7.9.0",
"mockery/mockery": "^1.4",
"nunomaduro/larastan": "^2.0",
"nunomaduro/phpinsights": "^2.7",
@ -94,7 +93,6 @@
},
"autoload-dev": {
"classmap": [
"tests/DuskTestCase.php",
"tests/TestCase.php"
],
"psr-4": {

413
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7ae0b408bfe4312a67752d97db504e3b",
"content-hash": "411741edf87445a87a6b771e1d370a09",
"packages": [
{
"name": "alek13/slack",
@ -188,16 +188,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.279.7",
"version": "3.281.2",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "223f97f8f12765b42a682569b434ac0210cca93a"
"reference": "5b33690b4ebc32a75164be0d6805d393a3ca9df9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/223f97f8f12765b42a682569b434ac0210cca93a",
"reference": "223f97f8f12765b42a682569b434ac0210cca93a",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5b33690b4ebc32a75164be0d6805d393a3ca9df9",
"reference": "5b33690b4ebc32a75164be0d6805d393a3ca9df9",
"shasum": ""
},
"require": {
@ -277,9 +277,9 @@
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.279.7"
"source": "https://github.com/aws/aws-sdk-php/tree/3.281.2"
},
"time": "2023-08-25T18:07:43+00:00"
"time": "2023-09-07T18:06:59+00:00"
},
{
"name": "bacon/bacon-qr-code",
@ -2477,16 +2477,16 @@
},
{
"name": "laravel/framework",
"version": "v10.20.0",
"version": "v10.22.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "a655dca3fbe83897e22adff652b1878ba352d041"
"reference": "9234388a895206d4e1df37342b61adc67e5c5d31"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/a655dca3fbe83897e22adff652b1878ba352d041",
"reference": "a655dca3fbe83897e22adff652b1878ba352d041",
"url": "https://api.github.com/repos/laravel/framework/zipball/9234388a895206d4e1df37342b61adc67e5c5d31",
"reference": "9234388a895206d4e1df37342b61adc67e5c5d31",
"shasum": ""
},
"require": {
@ -2673,7 +2673,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2023-08-22T13:37:09+00:00"
"time": "2023-09-05T13:20:01+00:00"
},
{
"name": "laravel/helpers",
@ -2733,16 +2733,16 @@
},
{
"name": "laravel/passport",
"version": "v11.8.8",
"version": "v11.9.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/passport.git",
"reference": "401836130d46c94138a637ada29f9e5b2bf053b6"
"reference": "93bb9c36045fe5be2eaeacf35e836c00b392b761"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/passport/zipball/401836130d46c94138a637ada29f9e5b2bf053b6",
"reference": "401836130d46c94138a637ada29f9e5b2bf053b6",
"url": "https://api.github.com/repos/laravel/passport/zipball/93bb9c36045fe5be2eaeacf35e836c00b392b761",
"reference": "93bb9c36045fe5be2eaeacf35e836c00b392b761",
"shasum": ""
},
"require": {
@ -2807,7 +2807,7 @@
"issues": "https://github.com/laravel/passport/issues",
"source": "https://github.com/laravel/passport"
},
"time": "2023-07-07T06:37:11+00:00"
"time": "2023-09-01T14:20:24+00:00"
},
{
"name": "laravel/prompts",
@ -2980,16 +2980,16 @@
},
{
"name": "laravel/socialite",
"version": "v5.8.1",
"version": "v5.9.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/socialite.git",
"reference": "9989b4530331597fae811bca240bf4e8f15e804b"
"reference": "14acfa3262875f180fba51efe3c7aaa089a9ef24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/socialite/zipball/9989b4530331597fae811bca240bf4e8f15e804b",
"reference": "9989b4530331597fae811bca240bf4e8f15e804b",
"url": "https://api.github.com/repos/laravel/socialite/zipball/14acfa3262875f180fba51efe3c7aaa089a9ef24",
"reference": "14acfa3262875f180fba51efe3c7aaa089a9ef24",
"shasum": ""
},
"require": {
@ -3046,20 +3046,20 @@
"issues": "https://github.com/laravel/socialite/issues",
"source": "https://github.com/laravel/socialite"
},
"time": "2023-08-21T13:06:52+00:00"
"time": "2023-09-05T15:20:21+00:00"
},
{
"name": "laravel/tinker",
"version": "v2.8.1",
"version": "v2.8.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/tinker.git",
"reference": "04a2d3bd0d650c0764f70bf49d1ee39393e4eb10"
"reference": "b936d415b252b499e8c3b1f795cd4fc20f57e1f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/tinker/zipball/04a2d3bd0d650c0764f70bf49d1ee39393e4eb10",
"reference": "04a2d3bd0d650c0764f70bf49d1ee39393e4eb10",
"url": "https://api.github.com/repos/laravel/tinker/zipball/b936d415b252b499e8c3b1f795cd4fc20f57e1f3",
"reference": "b936d415b252b499e8c3b1f795cd4fc20f57e1f3",
"shasum": ""
},
"require": {
@ -3072,6 +3072,7 @@
},
"require-dev": {
"mockery/mockery": "~1.3.3|^1.4.2",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^8.5.8|^9.3.3"
},
"suggest": {
@ -3112,9 +3113,9 @@
],
"support": {
"issues": "https://github.com/laravel/tinker/issues",
"source": "https://github.com/laravel/tinker/tree/v2.8.1"
"source": "https://github.com/laravel/tinker/tree/v2.8.2"
},
"time": "2023-02-15T16:40:09+00:00"
"time": "2023-08-15T14:27:00+00:00"
},
{
"name": "laravel/ui",
@ -3391,16 +3392,16 @@
},
{
"name": "league/commonmark",
"version": "2.4.0",
"version": "2.4.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
"reference": "d44a24690f16b8c1808bf13b1bd54ae4c63ea048"
"reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d44a24690f16b8c1808bf13b1bd54ae4c63ea048",
"reference": "d44a24690f16b8c1808bf13b1bd54ae4c63ea048",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/3669d6d5f7a47a93c08ddff335e6d945481a1dd5",
"reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5",
"shasum": ""
},
"require": {
@ -3493,7 +3494,7 @@
"type": "tidelift"
}
],
"time": "2023-03-24T15:16:10+00:00"
"time": "2023-08-30T16:55:00+00:00"
},
{
"name": "league/config",
@ -4155,20 +4156,20 @@
},
{
"name": "league/uri",
"version": "7.1.0",
"version": "7.2.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri.git",
"reference": "c0bf6dfa86b7804fe870b3f3d9c653e35a2c9e3e"
"reference": "8b644f8ff80352530bbc0ea467d5b5a89b60d832"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/uri/zipball/c0bf6dfa86b7804fe870b3f3d9c653e35a2c9e3e",
"reference": "c0bf6dfa86b7804fe870b3f3d9c653e35a2c9e3e",
"url": "https://api.github.com/repos/thephpleague/uri/zipball/8b644f8ff80352530bbc0ea467d5b5a89b60d832",
"reference": "8b644f8ff80352530bbc0ea467d5b5a89b60d832",
"shasum": ""
},
"require": {
"league/uri-interfaces": "^7.1",
"league/uri-interfaces": "^7.2",
"php": "^8.1"
},
"conflict": {
@ -4233,7 +4234,7 @@
"docs": "https://uri.thephpleague.com",
"forum": "https://thephpleague.slack.com",
"issues": "https://github.com/thephpleague/uri-src/issues",
"source": "https://github.com/thephpleague/uri/tree/7.1.0"
"source": "https://github.com/thephpleague/uri/tree/7.2.1"
},
"funding": [
{
@ -4241,20 +4242,20 @@
"type": "github"
}
],
"time": "2023-08-21T20:15:03+00:00"
"time": "2023-08-30T21:06:57+00:00"
},
{
"name": "league/uri-interfaces",
"version": "7.1.0",
"version": "7.2.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri-interfaces.git",
"reference": "c3ea9306c67c9a1a72312705e8adfcb9cf167310"
"reference": "43fa071050fcba89aefb5d4789a4a5a73874c44b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c3ea9306c67c9a1a72312705e8adfcb9cf167310",
"reference": "c3ea9306c67c9a1a72312705e8adfcb9cf167310",
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/43fa071050fcba89aefb5d4789a4a5a73874c44b",
"reference": "43fa071050fcba89aefb5d4789a4a5a73874c44b",
"shasum": ""
},
"require": {
@ -4317,7 +4318,7 @@
"docs": "https://uri.thephpleague.com",
"forum": "https://thephpleague.slack.com",
"issues": "https://github.com/thephpleague/uri-src/issues",
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.1.0"
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.2.0"
},
"funding": [
{
@ -4325,7 +4326,7 @@
"type": "github"
}
],
"time": "2023-08-21T20:15:03+00:00"
"time": "2023-08-30T19:43:38+00:00"
},
{
"name": "livewire/livewire",
@ -4743,16 +4744,16 @@
},
{
"name": "nesbot/carbon",
"version": "2.69.0",
"version": "2.70.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "4308217830e4ca445583a37d1bf4aff4153fa81c"
"reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4308217830e4ca445583a37d1bf4aff4153fa81c",
"reference": "4308217830e4ca445583a37d1bf4aff4153fa81c",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d3298b38ea8612e5f77d38d1a99438e42f70341d",
"reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d",
"shasum": ""
},
"require": {
@ -4845,7 +4846,7 @@
"type": "tidelift"
}
],
"time": "2023-08-03T09:00:52+00:00"
"time": "2023-09-07T16:43:50+00:00"
},
{
"name": "nette/schema",
@ -7861,16 +7862,16 @@
},
{
"name": "spatie/laravel-backup",
"version": "8.3.1",
"version": "8.3.3",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-backup.git",
"reference": "3a86fbc39d04f52024dfd57a334a078748e1b5f5"
"reference": "a20718e833daa77a8f496fb06ac208521669a838"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-backup/zipball/3a86fbc39d04f52024dfd57a334a078748e1b5f5",
"reference": "3a86fbc39d04f52024dfd57a334a078748e1b5f5",
"url": "https://api.github.com/repos/spatie/laravel-backup/zipball/a20718e833daa77a8f496fb06ac208521669a838",
"reference": "a20718e833daa77a8f496fb06ac208521669a838",
"shasum": ""
},
"require": {
@ -7944,7 +7945,7 @@
],
"support": {
"issues": "https://github.com/spatie/laravel-backup/issues",
"source": "https://github.com/spatie/laravel-backup/tree/8.3.1"
"source": "https://github.com/spatie/laravel-backup/tree/8.3.3"
},
"funding": [
{
@ -7956,7 +7957,7 @@
"type": "other"
}
],
"time": "2023-08-10T07:53:36+00:00"
"time": "2023-09-04T13:41:27+00:00"
},
{
"name": "spatie/laravel-ignition",
@ -10692,16 +10693,16 @@
},
{
"name": "tecnickcom/tc-lib-barcode",
"version": "1.17.25",
"version": "1.17.29",
"source": {
"type": "git",
"url": "https://github.com/tecnickcom/tc-lib-barcode.git",
"reference": "2b87f7c63dfd05000445a202c1779aeb9eb4549d"
"reference": "bbada6319c7999b51430408359af389cdc5442c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tecnickcom/tc-lib-barcode/zipball/2b87f7c63dfd05000445a202c1779aeb9eb4549d",
"reference": "2b87f7c63dfd05000445a202c1779aeb9eb4549d",
"url": "https://api.github.com/repos/tecnickcom/tc-lib-barcode/zipball/bbada6319c7999b51430408359af389cdc5442c8",
"reference": "bbada6319c7999b51430408359af389cdc5442c8",
"shasum": ""
},
"require": {
@ -10728,7 +10729,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
"LGPL-3.0-or-later"
],
"authors": [
{
@ -10778,7 +10779,7 @@
],
"support": {
"issues": "https://github.com/tecnickcom/tc-lib-barcode/issues",
"source": "https://github.com/tecnickcom/tc-lib-barcode/tree/1.17.25"
"source": "https://github.com/tecnickcom/tc-lib-barcode/tree/1.17.29"
},
"funding": [
{
@ -10786,20 +10787,20 @@
"type": "custom"
}
],
"time": "2023-05-18T08:10:11+00:00"
"time": "2023-09-06T13:20:35+00:00"
},
{
"name": "tecnickcom/tc-lib-color",
"version": "1.14.24",
"version": "1.14.28",
"source": {
"type": "git",
"url": "https://github.com/tecnickcom/tc-lib-color.git",
"reference": "6207533413f6edc3fea373d0e54041661d2bd905"
"reference": "c0ea9b1a8488776d33ae4051aa0701facf79e402"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tecnickcom/tc-lib-color/zipball/6207533413f6edc3fea373d0e54041661d2bd905",
"reference": "6207533413f6edc3fea373d0e54041661d2bd905",
"url": "https://api.github.com/repos/tecnickcom/tc-lib-color/zipball/c0ea9b1a8488776d33ae4051aa0701facf79e402",
"reference": "c0ea9b1a8488776d33ae4051aa0701facf79e402",
"shasum": ""
},
"require": {
@ -10822,7 +10823,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
"LGPL-3.0-or-later"
],
"authors": [
{
@ -10849,7 +10850,7 @@
],
"support": {
"issues": "https://github.com/tecnickcom/tc-lib-color/issues",
"source": "https://github.com/tecnickcom/tc-lib-color/tree/1.14.24"
"source": "https://github.com/tecnickcom/tc-lib-color/tree/1.14.28"
},
"funding": [
{
@ -10857,20 +10858,20 @@
"type": "custom"
}
],
"time": "2023-05-18T08:09:02+00:00"
"time": "2023-09-06T13:19:19+00:00"
},
{
"name": "tecnickcom/tcpdf",
"version": "6.6.2",
"version": "6.6.5",
"source": {
"type": "git",
"url": "https://github.com/tecnickcom/TCPDF.git",
"reference": "e3cffc9bcbc76e89e167e9eb0bbda0cab7518459"
"reference": "5fce932fcee4371865314ab7f6c0d85423c5c7ce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/e3cffc9bcbc76e89e167e9eb0bbda0cab7518459",
"reference": "e3cffc9bcbc76e89e167e9eb0bbda0cab7518459",
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/5fce932fcee4371865314ab7f6c0d85423c5c7ce",
"reference": "5fce932fcee4371865314ab7f6c0d85423c5c7ce",
"shasum": ""
},
"require": {
@ -10899,7 +10900,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-only"
"LGPL-3.0-or-later"
],
"authors": [
{
@ -10921,7 +10922,7 @@
],
"support": {
"issues": "https://github.com/tecnickcom/TCPDF/issues",
"source": "https://github.com/tecnickcom/TCPDF/tree/6.6.2"
"source": "https://github.com/tecnickcom/TCPDF/tree/6.6.5"
},
"funding": [
{
@ -10929,7 +10930,7 @@
"type": "custom"
}
],
"time": "2022-12-17T10:28:59+00:00"
"time": "2023-09-06T15:09:26+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
@ -11909,16 +11910,16 @@
},
{
"name": "composer/semver",
"version": "3.3.2",
"version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": ""
},
"require": {
@ -11968,9 +11969,9 @@
"versioning"
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2"
"source": "https://github.com/composer/semver/tree/3.4.0"
},
"funding": [
{
@ -11986,7 +11987,7 @@
"type": "tidelift"
}
],
"time": "2022-04-01T19:23:25+00:00"
"time": "2023-08-31T09:50:34+00:00"
},
{
"name": "composer/xdebug-handler",
@ -12169,82 +12170,6 @@
},
"time": "2019-12-04T15:06:13+00:00"
},
{
"name": "doctrine/annotations",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
"shasum": ""
},
"require": {
"doctrine/lexer": "^2 || ^3",
"ext-tokenizer": "*",
"php": "^7.2 || ^8.0",
"psr/cache": "^1 || ^2 || ^3"
},
"require-dev": {
"doctrine/cache": "^2.0",
"doctrine/coding-standard": "^10",
"phpstan/phpstan": "^1.8.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"symfony/cache": "^5.4 || ^6",
"vimeo/psalm": "^4.10"
},
"suggest": {
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
"keywords": [
"annotations",
"docblock",
"parser"
],
"support": {
"issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/2.0.1"
},
"time": "2023-02-02T22:02:53+00:00"
},
{
"name": "fakerphp/faker",
"version": "v1.23.0",
@ -12477,23 +12402,21 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.23.0",
"version": "v3.25.1",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "35af3cbbacfa91e164b252a28ec0b644f1ed4e78"
"reference": "8e21d69801de6b5ecb0dbe0bcdf967b335b1260b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/35af3cbbacfa91e164b252a28ec0b644f1ed4e78",
"reference": "35af3cbbacfa91e164b252a28ec0b644f1ed4e78",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/8e21d69801de6b5ecb0dbe0bcdf967b335b1260b",
"reference": "8e21d69801de6b5ecb0dbe0bcdf967b335b1260b",
"shasum": ""
},
"require": {
"composer/semver": "^3.3",
"composer/xdebug-handler": "^3.0.3",
"doctrine/annotations": "^2",
"doctrine/lexer": "^2 || ^3",
"ext-json": "*",
"ext-tokenizer": "*",
"php": "^7.4 || ^8.0",
@ -12562,7 +12485,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.23.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.25.1"
},
"funding": [
{
@ -12570,7 +12493,7 @@
"type": "github"
}
],
"time": "2023-08-14T12:27:35+00:00"
"time": "2023-09-04T01:22:52+00:00"
},
{
"name": "hamcrest/hamcrest-php",
@ -12752,82 +12675,6 @@
},
"time": "2022-04-13T08:02:27+00:00"
},
{
"name": "laravel/dusk",
"version": "v7.9.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/dusk.git",
"reference": "8d7ce583fb362472558cc1852adccfcd86cf87e4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/dusk/zipball/8d7ce583fb362472558cc1852adccfcd86cf87e4",
"reference": "8d7ce583fb362472558cc1852adccfcd86cf87e4",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-zip": "*",
"guzzlehttp/guzzle": "^7.2",
"illuminate/console": "^9.0|^10.0",
"illuminate/support": "^9.0|^10.0",
"nesbot/carbon": "^2.0",
"php": "^8.0",
"php-webdriver/webdriver": "^1.9.0",
"symfony/console": "^6.0",
"symfony/finder": "^6.0",
"symfony/process": "^6.0",
"vlucas/phpdotenv": "^5.2"
},
"require-dev": {
"mockery/mockery": "^1.4.2",
"orchestra/testbench": "^7.0|^8.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.5.10|^10.0.1",
"psy/psysh": "^0.11.12"
},
"suggest": {
"ext-pcntl": "Used to gracefully terminate Dusk when tests are running."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "7.x-dev"
},
"laravel": {
"providers": [
"Laravel\\Dusk\\DuskServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Dusk\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Laravel Dusk provides simple end-to-end testing and browser automation.",
"keywords": [
"laravel",
"testing",
"webdriver"
],
"support": {
"issues": "https://github.com/laravel/dusk/issues",
"source": "https://github.com/laravel/dusk/tree/v7.9.3"
},
"time": "2023-08-03T16:00:26+00:00"
},
{
"name": "league/container",
"version": "4.2.0",
@ -13475,72 +13322,6 @@
},
"time": "2022-02-21T12:50:22+00:00"
},
{
"name": "php-webdriver/webdriver",
"version": "1.14.0",
"source": {
"type": "git",
"url": "https://github.com/php-webdriver/php-webdriver.git",
"reference": "3ea4f924afb43056bf9c630509e657d951608563"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3ea4f924afb43056bf9c630509e657d951608563",
"reference": "3ea4f924afb43056bf9c630509e657d951608563",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-zip": "*",
"php": "^7.3 || ^8.0",
"symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^5.0 || ^6.0"
},
"replace": {
"facebook/webdriver": "*"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.20.0",
"ondram/ci-detector": "^4.0",
"php-coveralls/php-coveralls": "^2.4",
"php-mock/php-mock-phpunit": "^2.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpunit/phpunit": "^9.3",
"squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^5.0 || ^6.0"
},
"suggest": {
"ext-SimpleXML": "For Firefox profile creation"
},
"type": "library",
"autoload": {
"files": [
"lib/Exception/TimeoutException.php"
],
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.",
"homepage": "https://github.com/php-webdriver/php-webdriver",
"keywords": [
"Chromedriver",
"geckodriver",
"php",
"selenium",
"webdriver"
],
"support": {
"issues": "https://github.com/php-webdriver/php-webdriver/issues",
"source": "https://github.com/php-webdriver/php-webdriver/tree/1.14.0"
},
"time": "2023-02-09T12:12:19+00:00"
},
{
"name": "phpmyadmin/sql-parser",
"version": "5.8.0",
@ -13630,16 +13411,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.10.32",
"version": "1.10.33",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "c47e47d3ab03137c0e121e77c4d2cb58672f6d44"
"reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c47e47d3ab03137c0e121e77c4d2cb58672f6d44",
"reference": "c47e47d3ab03137c0e121e77c4d2cb58672f6d44",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"shasum": ""
},
"require": {
@ -13688,7 +13469,7 @@
"type": "tidelift"
}
],
"time": "2023-08-24T21:54:50+00:00"
"time": "2023-09-04T12:20:53+00:00"
},
{
"name": "phpunit/php-code-coverage",

View file

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddLastCheckinToAssets extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('assets', function (Blueprint $table) {
$table->dateTime('last_checkin')->after('last_checkout')->nullable();
});
DB::statement(
"UPDATE " . DB::getTablePrefix() . "assets SET last_checkin=(SELECT MAX(" . DB::getTablePrefix() . "action_logs.action_date) FROM " . DB::getTablePrefix() . "action_logs WHERE item_type='App\\\Models\\\Asset' AND " . DB::getTablePrefix() . "action_logs.item_id=" . DB::getTablePrefix() . "assets.id AND " . DB::getTablePrefix() . "action_logs.action_type='checkin from')"
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('assets', function (Blueprint $table) {
$table->dropColumn('last_checkin');
});
}
}

View file

@ -2,6 +2,7 @@
return [
'does_not_exist' => 'Company does not exist.',
'deleted' => 'Deleted company',
'assoc_users' => 'This company is currently associated with at least one model and cannot be deleted. Please update your models to no longer reference this company and try again. ',
'create' => [
'error' => 'Company was not created, please try again.',

View file

@ -14,6 +14,7 @@ return [
'dl_csv' => 'Download CSV',
'eol' => 'EOL',
'id' => 'ID',
'last_checkin_date' => 'Last Checkin Date',
'location' => 'Location',
'purchase_cost' => 'Cost',
'purchase_date' => 'Purchased',

View file

@ -2,7 +2,7 @@
return array(
'support_url_help' => 'Use <code>{LOCALE}</code> and <code>{SERIAL}</code> in your URL as variables to have those values auto-populate when viewing assets.',
'support_url_help' => 'Variables <code>{LOCALE}</code>, <code>{SERIAL}</code>, <code>{MODEL_NUMBER}</code>, and <code>{MODEL_NAME}</code> may be used in your URL to have those values auto-populate when viewing assets - for example https://support.apple.com/{LOCALE}/{SERIAL}.',
'does_not_exist' => 'Manufacturer does not exist.',
'assoc_users' => 'This manufacturer is currently associated with at least one model and cannot be deleted. Please update your models to no longer reference this manufacturer and try again. ',

View file

@ -2,6 +2,7 @@
return array(
'deleted' => 'Deleted asset model',
'does_not_exist' => 'Model does not exist.',
'no_association' => 'WARNING! The asset model for this item is invalid or missing!',
'no_association_fix' => 'This will break things in weird and horrible ways. Edit this asset now to assign it a model.',

View file

@ -2,6 +2,7 @@
return array(
'deleted' => 'Deleted supplier',
'does_not_exist' => 'Supplier does not exist.',

View file

@ -29,6 +29,7 @@ return array(
'show_deleted' => 'Show Deleted Users',
'title' => 'Title',
'to_restore_them' => 'to restore them.',
'total_assets_cost' => "Total Assets Cost",
'updateuser' => 'Update User',
'username' => 'Username',
'user_deleted_text' => 'This user has been marked as deleted.',

View file

@ -141,6 +141,11 @@
{{ trans('admin/hardware/table.checkout_date') }}
</label>
<label class="form-control">
{{ Form::checkbox('checkin_date', '1', '1') }}
{{ trans('admin/hardware/table.last_checkin_date') }}
</label>
<label class="form-control">
{{ Form::checkbox('expected_checkin', '1', '1') }}
{{ trans('admin/hardware/form.expected_checkin') }}
@ -289,6 +294,16 @@
</div>
</div>
<!-- Last Checkin Date -->
<div class="form-group checkin-range">
<label for="checkin_date" class="col-md-3 control-label">{{ trans('admin/hardware/table.last_checkin_date') }}</label>
<div class="input-daterange input-group col-md-6" id="datepicker">
<input type="text" class="form-control" name="checkin_date_start" aria-label="checkin_date_start">
<span class="input-group-addon">{{ strtolower(trans('general.to')) }}</span>
<input type="text" class="form-control" name="checkin_date_end" aria-label="checkin_date_end">
</div>
</div>
<!-- Expected Checkin Date -->
<div class="form-group expected_checkin-range">
<label for="expected_checkin_start" class="col-md-3 control-label">{{ trans('admin/hardware/form.expected_checkin') }}</label>
@ -381,6 +396,13 @@
format: 'yyyy-mm-dd'
});
$('.checkin-range .input-daterange').datepicker({
clearBtn: true,
todayHighlight: true,
endDate: '0d',
format: 'yyyy-mm-dd'
});
$('.expected_checkin-range .input-daterange').datepicker({
clearBtn: true,
todayHighlight: true,

View file

@ -638,6 +638,27 @@
</div>
@endif
<div class="row">
<div class="col-md-3">
{{ trans('admin/users/table.total_assets_cost') }}
</div>
<div class="col-md-9">
{{Helper::formatCurrencyOutput($user->getUserTotalCost()->total_user_cost)}}
<a id="optional_info" class="text-primary">
<i class="fa fa-caret-right fa-2x" id="optional_info_icon"></i>
<strong>{{ trans('admin/hardware/form.optional_infos') }}</strong>
</a>
</div>
<div id="optional_details" class="col-md-12" style="display:none">
<div class="col-md-3" style="border-top:none;"></div>
<div class="col-md-9" style="border-top:none;">
{{trans('general.assets').': '. Helper::formatCurrencyOutput($user->getUserTotalCost()->asset_cost)}}<br>
{{trans('general.licenses').': '. Helper::formatCurrencyOutput($user->getUserTotalCost()->license_cost)}}<br>
{{trans('general.accessories').': '.Helper::formatCurrencyOutput($user->getUserTotalCost()->accessory_cost)}}<br>
</div>
</div>
</div>
</div> <!--/end striped container-->
</div> <!-- end col-md-9 -->
@ -1109,6 +1130,12 @@ $(function () {
}
});
$("#optional_info").on("click",function(){
$('#optional_details').fadeToggle(100);
$('#optional_info_icon').toggleClass('fa-caret-right fa-caret-down');
var optional_info_open = $('#optional_info_icon').hasClass('fa-caret-down');
document.cookie = "optional_info_open="+optional_info_open+'; path=/';
});
});
</script>

View file

@ -1,46 +0,0 @@
<?php
namespace Tests\Browser;
use App\Models\Setting;
use App\Models\User;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class LoginTest extends DuskTestCase
{
/**
* Test login
*
* @return void
*/
public function testLoginPageLoadsAndUserCanLogin()
{
// Create a new user
$user = User::factory()->make();
// We override the existing password to use a hash of one we know
$user->password = '$2y$10$8o5W8fgAKJbN3Kz4taepeeRVgKsG8pkZ1L4eJfdEKrn2mgI/JgCJy';
// We want a user that is a superuser
$user->permissions = '{"superuser": 1}';
$user->save();
Setting::factory()->create();
$this->browse(function (Browser $browser) {
$browser->visitRoute('login')
->assertSee(trans('auth/general.login_prompt'));
});
$this->browse(function ($browser) use ($user) {
$browser->visitRoute('login')
->type('username', $user->username)
->type('password', 'password')
->press(trans('auth/general.login'))
->assertPathIs('/');
$browser->screenshot('dashboard');
});
}
}

View file

@ -1,41 +0,0 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
class HomePage extends Page
{
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/';
}
/**
* Assert that the browser is on the page.
*
* @param \Laravel\Dusk\Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
//
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'@element' => '#selector',
];
}
}

View file

@ -1,20 +0,0 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Page as BasePage;
abstract class Page extends BasePage
{
/**
* Get the global element shortcuts for the site.
*
* @return array
*/
public static function siteElements()
{
return [
'@element' => '#selector',
];
}
}

View file

@ -1,2 +0,0 @@
*
!.gitignore

View file

@ -1,2 +0,0 @@
*
!.gitignore

View file

@ -1,2 +0,0 @@
*
!.gitignore

View file

@ -1,70 +0,0 @@
<?php
namespace Tests;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\TestCase as BaseTestCase;
use RuntimeException;
abstract class DuskTestCase extends BaseTestCase
{
use CreatesApplication;
use DatabaseMigrations;
/**
* Prepare for Dusk test execution.
*
* @beforeClass
* @return void
*/
public static function prepare()
{
if (!file_exists(realpath(__DIR__ . '/../') . '/.env.dusk.local')) {
throw new RuntimeException(
'.env.dusk.local file does not exist. Aborting to avoid wiping your local database'
);
}
if (! static::runningInSail()) {
static::startChromeDriver();
}
}
/**
* Create the RemoteWebDriver instance.
*
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
$options = (new ChromeOptions)->addArguments(collect([
'--window-size=1920,1080',
])->unless($this->hasHeadlessDisabled(), function ($items) {
return $items->merge([
'--disable-gpu',
'--headless',
]);
})->all());
return RemoteWebDriver::create(
$_ENV['DUSK_DRIVER_URL'] ?? 'http://127.0.0.1:9515',
DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY, $options
)
);
}
/**
* Determine whether the Dusk command has disabled headless mode.
*
* @return bool
*/
protected function hasHeadlessDisabled()
{
return isset($_SERVER['DUSK_HEADLESS_DISABLED']) ||
isset($_ENV['DUSK_HEADLESS_DISABLED']);
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace Tests\Feature\Api\Assets;
use App\Models\Asset;
use App\Models\User;
use Tests\Support\InteractsWithSettings;
use Tests\TestCase;
class AssetCheckinTest extends TestCase
{
use InteractsWithSettings;
public function testLastCheckInFieldIsSetOnCheckin()
{
$admin = User::factory()->superuser()->create();
$asset = Asset::factory()->create(['last_checkin' => null]);
$asset->checkOut(User::factory()->create(), $admin, now());
$this->actingAsForApi($admin)
->postJson(route('api.asset.checkin', $asset))
->assertOk();
$this->assertNotNull(
$asset->fresh()->last_checkin,
'last_checkin field should be set on checkin'
);
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Tests\Feature\Assets;
use App\Models\Asset;
use App\Models\User;
use Tests\Support\InteractsWithSettings;
use Tests\TestCase;
class AssetCheckinTest extends TestCase
{
use InteractsWithSettings;
public function testLastCheckInFieldIsSetOnCheckin()
{
$admin = User::factory()->superuser()->create();
$asset = Asset::factory()->create(['last_checkin' => null]);
$asset->checkOut(User::factory()->create(), $admin, now());
$this->actingAs($admin)
->post(route('hardware.checkin.store', [
'assetId' => $asset->id,
]))
->assertRedirect();
$this->assertNotNull(
$asset->fresh()->last_checkin,
'last_checkin field should be set on checkin'
);
}
}

View file

@ -107,4 +107,29 @@ class CustomReportTest extends TestCase
->assertDontSeeTextInStreamedResponse('Asset A')
->assertSeeTextInStreamedResponse('Asset B');
}
public function testCanLimitAssetsByLastCheckIn()
{
Asset::factory()->create(['name' => 'Asset A', 'last_checkin' => '2023-08-01']);
Asset::factory()->create(['name' => 'Asset B', 'last_checkin' => '2023-08-02']);
Asset::factory()->create(['name' => 'Asset C', 'last_checkin' => '2023-08-03']);
Asset::factory()->create(['name' => 'Asset D', 'last_checkin' => '2023-08-04']);
Asset::factory()->create(['name' => 'Asset E', 'last_checkin' => '2023-08-05']);
$this->actingAs(User::factory()->canViewReports()->create())
->post('reports/custom', [
'asset_name' => '1',
'asset_tag' => '1',
'serial' => '1',
'checkin_date' => '1',
'checkin_date_start' => '2023-08-02',
'checkin_date_end' => '2023-08-04',
])->assertOk()
->assertHeader('content-type', 'text/csv; charset=UTF-8')
->assertDontSeeTextInStreamedResponse('Asset A')
->assertSeeTextInStreamedResponse('Asset B')
->assertSeeTextInStreamedResponse('Asset C')
->assertSeeTextInStreamedResponse('Asset D')
->assertDontSeeTextInStreamedResponse('Asset E');
}
}