3
0
mirror of https://github.com/snipe/snipe-it.git synced 2025-10-29 19:31:41 +00:00

Merge remote-tracking branch 'origin/develop'

# Conflicts:
#	public/css/build/app.css
#	public/css/build/app.css.map
#	public/css/build/overrides.css
#	public/css/build/overrides.css.map
#	public/css/dist/all.css
#	public/mix-manifest.json
This commit is contained in:
snipe 2025-09-19 12:44:49 +01:00
commit 0b60c6a939
22 changed files with 99 additions and 8 deletions

View File

@ -647,6 +647,15 @@ class BulkAssetsController extends Controller
$assets = Asset::findOrFail($asset_ids);
// Prevent checking out assets that are already checked out
if ($assets->pluck('assigned_to')->unique()->filter()->isNotEmpty()) {
// re-add the asset ids so the assets select is re-populated
$request->session()->flashInput(['selected_assets' => $asset_ids]);
return redirect(route('hardware.bulkcheckout.show'))
->with('error', trans('general.error_assets_already_checked_out'));
}
if (request('checkout_to_type') == 'asset') {
foreach ($asset_ids as $asset_id) {
if ($target->id == $asset_id) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,8 +2,8 @@
"/js/dist/all.js": "/js/dist/all.js?id=5c191843e0bb9292ec6b7f0a3c5765b3",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=bf1a348eae3e60c62b8879953f7df14c",
"/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=146086d653897e2557af5e68f6f8c56f",
"/css/build/overrides.css": "/css/build/overrides.css?id=da2636d15880131386d4077637ec9be2",
"/css/build/app.css": "/css/build/app.css?id=813a3e9610d1108dbe35f62435d436fd",
"/css/build/overrides.css": "/css/build/overrides.css?id=3f6ab7e6902cca7d96e637b82dc95e65",
"/css/build/app.css": "/css/build/app.css?id=5876cf8fb09a66f8f9e0b2472c9cc9f8",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=bdf169bc2141f453390614c138cdce95",
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=e1e6e1c64cf14fc350585aaeb0e42f6b",
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=08ae1b3e66008966ce5d600ea3ad04a2",
@ -19,7 +19,7 @@
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=68a92d85c8e351dfb38a835307f126ec",
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=cbb20ad6182b658f34117bf96a621b63",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=84e2ee950ae04444988b37038e5a3951",
"/css/dist/all.css": "/css/dist/all.css?id=a480f24f1a8b590f3686e529fd25309b",
"/css/dist/all.css": "/css/dist/all.css?id=88a000a091cb26a138368945df92ab83",
"/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",
"/js/select2/i18n/af.js": "/js/select2/i18n/af.js?id=4f6fcd73488ce79fae1b7a90aceaecde",

View File

@ -1260,4 +1260,8 @@ caption.tableCaption {
clip: rect(0,0,0,0);
white-space: preserve;
display: inline-block;
}
input[name="columnsSearch"] {
width: 120px;
}

View File

@ -520,6 +520,7 @@ return [
'item_name_var' => ':item Name',
'error_user_company' => 'Checkout target company and asset company do not match',
'error_user_company_accept_view' => 'An Asset assigned to you belongs to a different company so you can\'t accept nor deny it, please check with your manager',
'error_assets_already_checked_out' => 'One or more of the assets are already checked out',
'importer' => [
'checked_out_to_fullname' => 'Checked Out to: Full Name',
'checked_out_to_first_name' => 'Checked Out to: First Name',

View File

@ -61,6 +61,7 @@
@if ($category->category_type=='asset')
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="categoryAssetsTable"
id="categoryAssetsTable"
data-buttons="assetButtons"

View File

@ -94,6 +94,7 @@
data-cookie-id-table="assetsListingTable"
data-id-table="assetsListingTable"
data-side-pagination="server"
data-show-columns-search="true"
data-sort-order="asc"
data-toolbar="#assetsBulkEditToolbar"
data-bulk-button-id="#bulkAssetEditButton"

View File

@ -65,6 +65,7 @@
<table
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="depreciationsAssetTable"
data-id-table="depreciationsAssetTable"
id="depreciationsAssetTable"

View File

@ -49,6 +49,7 @@
<table
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="dueAssetcheckinListing"
data-id-table="dueAssetcheckinListing"
data-side-pagination="server"

View File

@ -47,6 +47,8 @@
{{-- Page content --}}
@section('content')
<div class="row">
<div class="col-md-12">
<div class="box">
@ -66,6 +68,7 @@
data-show-footer="true"
data-sort-order="asc"
data-sort-name="name"
data-show-columns-search="true"
data-toolbar="#assetsBulkEditToolbar"
data-bulk-button-id="#bulkAssetEditButton"
data-bulk-form-id="#assetsBulkForm"

View File

@ -1285,6 +1285,7 @@
<table
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="assetsTable"
data-id-table="assetsTable"
data-side-pagination="server"

View File

@ -210,6 +210,7 @@
@include('partials.asset-bulk-actions')
<table
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="assetsListingTable"
data-id-table="assetsListingTable"
data-side-pagination="server"
@ -237,6 +238,7 @@
<table
role="table"
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="assetsAssignedListingTable"
data-id-table="assetsAssignedListingTable"
data-side-pagination="server"
@ -262,6 +264,7 @@
<table
role="table"
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="RTDassetsListingTable"
data-id-table="RTDassetsListingTable"
data-side-pagination="server"

View File

@ -104,6 +104,7 @@
<div class="table table-responsive">
<table
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="assetsListingTable"
data-id-table="assetsListingTable"
data-toolbar="#assetsBulkEditToolbar"

View File

@ -87,6 +87,7 @@
<table
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="assetListingTable"
data-id-table="assetListingTable"
data-side-pagination="server"

View File

@ -24,6 +24,7 @@
data-bulk-button-id="#bulkAssetEditButton"
data-bulk-form-id="#assetsBulkForm"
id="assetsListingTable"
data-show-columns-search="true"
data-buttons="assetButtons"
class="table table-striped snipe-table"
data-url="{{route('api.assets.index', ['status_id' => $statuslabel->id]) }}"

View File

@ -114,6 +114,7 @@
<table
data-cookie-id-table="suppliersAssetsTable"
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-id-table="suppliersAssetsTable"
data-show-footer="true"
data-side-pagination="server"

View File

@ -836,6 +836,7 @@
<table
data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-show-columns-search="true"
data-cookie-id-table="userAssetsListingTable"
data-id-table="userAssetsListingTable"
data-side-pagination="server"

View File

@ -4,8 +4,10 @@ namespace Tests\Feature\Checkouts\Ui;
use App\Mail\CheckoutAssetMail;
use App\Models\Asset;
use App\Models\Location;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\ExpectationFailedException;
use Tests\TestCase;
@ -89,4 +91,63 @@ class BulkAssetCheckoutTest extends TestCase
$this->fail('Asset checkout email was sent when the entire checkout failed.');
}
}
public static function checkoutTargets()
{
yield 'Checkout to user' => [
function () {
return [
'type' => 'user',
'target' => User::factory()->forCompany()->create(),
];
}
];
yield 'Checkout to asset' => [
function () {
return [
'type' => 'asset',
'target' => Asset::factory()->forCompany()->create(),
];
}
];
yield 'Checkout to location' => [
function () {
return [
'type' => 'location',
'target' => Location::factory()->forCompany()->create(),
];
}
];
}
#[DataProvider('checkoutTargets')]
public function test_prevents_checkouts_of_checked_out_items($data)
{
['type' => $type, 'target' => $target] = $data();
$asset = Asset::factory()->create();
$checkedOutAsset = Asset::factory()->assignedToUser()->create();
$existingUserId = $checkedOutAsset->assigned_to;
$response = $this->actingAs(User::factory()->superuser()->create())
->post(route('hardware.bulkcheckout.store'), [
'selected_assets' => [
$asset->id,
$checkedOutAsset->id,
],
'checkout_to_type' => $type,
"assigned_$type" => $target->id,
]);
$this->assertEquals(
$existingUserId,
$checkedOutAsset->fresh()->assigned_to,
'Asset was checked out when it should have been prevented.'
);
// ensure redirected back
$response->assertRedirectToRoute('hardware.bulkcheckout.show');
}
}