Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/Http/Controllers/Api/LicensesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public function index(Request $request) : JsonResponse | array

$licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count');

if ($request->input('status')=='inactive') {
$licenses->ExpiredLicenses();
} else {
$licenses->ActiveLicenses();
}

if ($request->filled('company_id')) {
$licenses->where('licenses.company_id', '=', $request->input('company_id'));
}
Expand Down Expand Up @@ -94,6 +100,8 @@ public function index(Request $request) : JsonResponse | array
$licenses->onlyTrashed();
}



// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $licenses->count()) ? $licenses->count() : app('api_offset_value');
$limit = app('api_limit_value');
Expand Down
19 changes: 18 additions & 1 deletion app/Http/Controllers/Licenses/LicenseCheckoutController.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class LicenseCheckoutController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
* @param $id
* @return \Illuminate\Contracts\View\View
* @return \Illuminate\Contracts\View\View |\Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(License $license)
Expand All @@ -39,6 +39,11 @@ public function create(License $license)
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
}

// Make sure the license is expired or terminated
if ($license->isInactive()){
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.license_is_inactive'));
}

// We don't currently allow checking out licenses to locations, so we'll reset that to user if needed
if (session()->get('checkout_to_type') == 'location') {
session()->put(['checkout_to_type' => 'user']);
Expand Down Expand Up @@ -70,8 +75,19 @@ public function store(LicenseCheckoutRequest $request, $licenseId, $seatId = nul
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
}


$this->authorize('checkout', $license);

// Make sure there is at least one available to checkout
if ($license->availCount()->count() < 1) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
}

// Make sure the license is expired or terminated
if ($license->isInactive()) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.license_is_inactive'));
}

$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId);
$licenseSeat->created_by = auth()->id();
$licenseSeat->notes = $request->input('notes');
Expand Down Expand Up @@ -114,6 +130,7 @@ protected function findLicenseSeatToCheckout($license, $seatId)
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats')));
}


if (! $licenseSeat->license->is($license)) {
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.mismatch')));
}
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Transformers/LicensesTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ public function transformLicense(License $license)
'purchase_order' => ($license->purchase_order) ? e($license->purchase_order) : null,
'purchase_date' => Helper::getFormattedDateObject($license->purchase_date, 'date'),
'termination_date' => Helper::getFormattedDateObject($license->termination_date, 'date'),
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
'depreciation' => ($license->depreciation) ? ['id' => (int) $license->depreciation->id,'name'=> e($license->depreciation->name)] : null,
'purchase_cost' => Helper::formatCurrencyOutput($license->purchase_cost),
'purchase_cost_numeric' => $license->purchase_cost,
'notes' => Helper::parseEscapedMarkedownInline($license->notes),
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
'seats' => (int) $license->seats,
'free_seats_count' => (int) $license->free_seats_count - License::unReassignableCount($license),
'remaining' => (int) $license->free_seats_count,
Expand Down
45 changes: 39 additions & 6 deletions app/Models/License.php
Original file line number Diff line number Diff line change
Expand Up @@ -299,16 +299,17 @@ public function setTerminationDateAttribute($value)
}

public function isInactive(): bool
{
$day = now()->startOfDay();
{
$day = now()->startOfDay();

$expired = $this->expiration_date && $this->asDateTime($this->expiration_date)->startofDay()->lessThanOrEqualTo($day);
$expired = $this->expiration_date && $this->asDateTime($this->expiration_date)->startofDay()->lessThanOrEqualTo($day);

$terminated = $this->termination_date && $this->asDateTime($this->termination_date)->startofDay()->lessThanOrEqualTo($day);
$terminated = $this->termination_date && $this->asDateTime($this->termination_date)->startofDay()->lessThanOrEqualTo($day);


return $expired || $terminated;
}
return $expired || $terminated;
}

/**
* Sets free_seat_count attribute
*
Expand Down Expand Up @@ -750,6 +751,38 @@ public static function getExpiringLicenses($days = 60)
->get();
}

public function scopeActiveLicenses($query)
{

return $query->whereNull('deleted_at')

// The termination date is null or within range
->where(function ($query) {
$query->whereNull('termination_date')
->orWhereDate('termination_date', '>', [Carbon::now()]);
})
->where(function ($query) {
$query->whereNull('expiration_date')
->orWhereDate('expiration_date', '>', [Carbon::now()]);
});
}

public function scopeExpiredLicenses($query)
{

return $query->whereNull('deleted_at')

// The termination date is null or within range
->where(function ($query) {
$query->whereNull('termination_date')
->orWhereDate('termination_date', '<=', [Carbon::now()]);
})
->orWhere(function ($query) {
$query->whereNull('expiration_date')
->orWhereDate('expiration_date', '<=', [Carbon::now()]);
});
}

/**
* Query builder scope to order on manufacturer
*
Expand Down
17 changes: 13 additions & 4 deletions app/Providers/BreadcrumbsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,19 @@ public function boot()
/**
* Licenses Breadcrumbs
*/
Breadcrumbs::for('licenses.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.licenses'), route('licenses.index'))
);
if ((request()->is('licenses*')) && (request()->status=='inactive')) {
Breadcrumbs::for('licenses.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.licenses'), route('licenses.index'))
->push(trans('general.show_inactive'), route('licenses.index'))
);
} else {
Breadcrumbs::for('licenses.index', fn (Trail $trail) =>
$trail->parent('home', route('home'))
->push(trans('general.licenses'), route('licenses.index'))
);
}


Breadcrumbs::for('licenses.create', fn (Trail $trail) =>
$trail->parent('licenses.index', route('licenses.index'))
Expand Down
4 changes: 2 additions & 2 deletions database/factories/LicenseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ public function definition()
'seats' => $this->faker->numberBetween(1, 10),
'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get())->format('Y-m-d'),
'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' => null,
'reassignable' => $this->faker->boolean(),
'termination_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get())->format('Y-m-d H:i:s'),
'termination_date' => null,
'supplier_id' => Supplier::factory(),
'category_id' => Category::factory(),
];
Expand Down
1 change: 1 addition & 0 deletions resources/lang/en-US/general.php
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@
'components' => ':count Component|:count Components',
],

'show_inactive' => 'Expired or Terminated',
'more_info' => 'More Info',
'quickscan_bulk_help' => 'Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log. Note that if this asset is checked out, it will not change the location of the person, asset or location it is checked out to.',
'whoops' => 'Whoops!',
Expand Down
2 changes: 1 addition & 1 deletion resources/views/licenses/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
id="licensesTable"
data-buttons="licenseButtons"
class="table table-striped snipe-table"
data-url="{{ route('api.licenses.index') }}"
data-url="{{ route('api.licenses.index', ['status' => e(request('status'))]) }}"
data-export-options='{
"fileName": "export-licenses-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
Expand Down
2 changes: 1 addition & 1 deletion resources/views/models/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
id="asssetModelsTable"
data-buttons="modelButtons"
class="table table-striped snipe-table"
data-url="{{ route('api.models.index', ['status' => request('status')]) }}"
data-url="{{ route('api.models.index', ['status' => e(request('status'))]) }}"
data-export-options='{
"fileName": "export-models-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
Expand Down
34 changes: 28 additions & 6 deletions resources/views/partials/bootstrap-table.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -557,12 +557,17 @@ function checkboxEnabledFormatter (value, row) {
}

function licenseInOutFormatter(value, row) {
if(row.disabled || row.user_can_checkout === false) {
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-maroon disabled" data-tooltip="true" title="{{ trans('general.checkin_tooltip') }}">{{ trans('general.checkout') }}</a>';

// check that checkin is not disabled
if (row.user_can_checkout === false) {
return '<span class="btn btn-sm bg-maroon disabled" data-tooltip="true" title="{{ trans('admin/licenses/message.checkout.unavailable') }}">{{ trans('general.checkout') }}</span>';
} else if (row.disabled === true) {
return '<span class="btn btn-sm bg-maroon disabled" data-tooltip="true" title="{{ trans('admin/licenses/message.checkout.license_is_inactive') }}">{{ trans('general.checkout') }}</span>';

} else
// The user is allowed to check the license seat out and it's available
if ((row.available_actions.checkout === true) && (row.user_can_checkout === true)) {
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkout/'+row.id+'" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
if ((row.available_actions.checkout === true) && (row.user_can_checkout === true) && (row.disabled === false)) {
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkout/" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
}
}
// We need a special formatter for license seats, since they don't work exactly the same
Expand All @@ -572,14 +577,19 @@ function licenseSeatInOutFormatter(value, row) {
if (row.disabled && (row.assigned_user || row.assigned_asset)) {
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="{{ trans('general.checkin_tooltip') }}">{{ trans('general.checkin') }}</a>';
}
if(row.disabled) {
if (row.disabled) {
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-maroon disabled" data-tooltip="true" title="{{ trans('general.checkin_tooltip') }}">{{ trans('general.checkout') }}</a>';
}
// The user is allowed to check the license seat out and it's available
if ((row.available_actions.checkout === true) && (row.user_can_checkout === true) && ((!row.assigned_asset) && (!row.assigned_user))) {
return '<a href="{{ config('app.url') }}/licenses/' + row.license_id + '/checkout/'+row.id+'" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
}

// The user is allowed to check the license seat in and it's available
if ((row.available_actions.checkin === true) && ((row.assigned_asset) || (row.assigned_user))) {
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin/" class="btn btn-sm bg-purple" data-tooltip="true" title="{{ trans('general.checkin_tooltip') }}">{{ trans('general.checkin') }}</a>';
}

}

function genericCheckinCheckoutFormatter(destination) {
Expand Down Expand Up @@ -1775,7 +1785,19 @@ class: 'btn btn-primary',
attributes: {
title: '{{ trans('general.export') }}'
}
}
},

btnShowInactive: {
text: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}',
icon: 'fas fa-clock {{ (request()->input('status') == "inactive") ? ' text-danger' : '' }}',
event () {
window.location.href = '{{ (request()->input('status') == "inactive") ? route('licenses.index') : route('licenses.index', ['status' => 'inactive']) }}';
},
attributes: {
title: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}',

}
},
});


Expand Down
2 changes: 1 addition & 1 deletion resources/views/users/view.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,7 @@ class="table table-striped snipe-table table-hover"
</td>
<td class="hidden-print col-md-2">
@can('update', $license)
<a href="{{ route('licenses.checkin', $license->pivot->id, ['backto'=>'user']) }}" class="btn btn-primary btn-sm hidden-print">{{ trans('general.checkin') }}</a>
<a href="{{ route('licenses.checkin', $license->pivot->id, ['backto'=>'user']) }}" class="btn bg-purple btn-sm hidden-print">{{ trans('general.checkin') }}</a>
@endcan
</td>
</tr>
Expand Down
Loading