mirror of
https://github.com/snipe/snipe-it.git
synced 2025-03-05 20:52:15 -08:00
Merge c47e63747b
into c9f55bfd94
This commit is contained in:
commit
e2680bd0e9
40
app/Actions/Assets/DestroyAssetAction.php
Normal file
40
app/Actions/Assets/DestroyAssetAction.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Actions\Assets;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Exception;
|
||||
|
||||
|
||||
class DestroyAssetAction
|
||||
{
|
||||
public static function run(Asset $asset)
|
||||
{
|
||||
if ($asset->assignedTo) {
|
||||
|
||||
$target = $asset->assignedTo;
|
||||
$checkin_at = date('Y-m-d H:i:s');
|
||||
$originalValues = $asset->getRawOriginal();
|
||||
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on delete', $checkin_at, $originalValues));
|
||||
DB::table('assets')
|
||||
->where('id', $asset->id)
|
||||
->update(['assigned_to' => null]);
|
||||
}
|
||||
|
||||
|
||||
if ($asset->image) {
|
||||
try {
|
||||
Storage::disk('public')->delete('assets'.'/'.$asset->image);
|
||||
} catch (Exception $e) {
|
||||
Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
$asset->delete();
|
||||
}
|
||||
|
||||
}
|
162
app/Actions/Assets/StoreAssetAction.php
Normal file
162
app/Actions/Assets/StoreAssetAction.php
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
namespace App\Actions\Assets;
|
||||
|
||||
use App\Exceptions\CheckoutNotAllowed;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class StoreAssetAction
|
||||
{
|
||||
/**
|
||||
* @throws CheckoutNotAllowed
|
||||
*/
|
||||
public static function run(
|
||||
$model_id,
|
||||
$status_id,//
|
||||
ImageUploadRequest $request, //temp for handleImages - i'd like to see that moved to a helper or something - or maybe just invoked at the extended request level so that it doesn't need to be done in the action?
|
||||
$name = null,
|
||||
$serial = null,
|
||||
$company_id = null,
|
||||
$asset_tag = null,
|
||||
$order_number = null,
|
||||
$notes = null,
|
||||
$warranty_months = null,
|
||||
$purchase_cost = null,
|
||||
$asset_eol_date = null,
|
||||
$purchase_date = null,
|
||||
$assigned_to = null,
|
||||
$supplier_id = null,
|
||||
$requestable = null,
|
||||
$rtd_location_id = null,
|
||||
$location_id = null,
|
||||
$byod = 0,
|
||||
$assigned_user = null,
|
||||
$assigned_asset = null,
|
||||
$assigned_location = null,
|
||||
$last_audit_date = null,
|
||||
$next_audit_date = null,
|
||||
): Asset|bool
|
||||
{
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
// initial setting up of asset
|
||||
$asset = new Asset();
|
||||
$asset->model()->associate(AssetModel::find($model_id));
|
||||
$asset->name = $name;
|
||||
$asset->serial = $serial;
|
||||
$asset->asset_tag = $asset_tag;
|
||||
$asset->company_id = Company::getIdForCurrentUser($company_id);
|
||||
$asset->model_id = $model_id;
|
||||
$asset->order_number = $order_number;
|
||||
$asset->notes = $notes;
|
||||
$asset->created_by = auth()->id();
|
||||
$asset->status_id = $status_id;
|
||||
$asset->warranty_months = $warranty_months;
|
||||
$asset->purchase_cost = $purchase_cost;
|
||||
$asset->purchase_date = $purchase_date;
|
||||
$asset->asset_eol_date = $asset_eol_date;
|
||||
$asset->assigned_to = $assigned_to;
|
||||
$asset->supplier_id = $supplier_id;
|
||||
$asset->requestable = $requestable;
|
||||
$asset->rtd_location_id = $rtd_location_id;
|
||||
$asset->byod = $byod;
|
||||
$asset->last_audit_date = $last_audit_date;
|
||||
$asset->next_audit_date = $next_audit_date;
|
||||
$asset->location_id = $location_id;
|
||||
|
||||
// set up next audit date
|
||||
if (!empty($settings->audit_interval) && is_null($next_audit_date)) {
|
||||
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
||||
}
|
||||
|
||||
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
|
||||
if (!$assigned_user && !$assigned_asset && !$assigned_location) {
|
||||
$asset->location_id = $rtd_location_id;
|
||||
}
|
||||
|
||||
$asset = self::handleImages($request, $asset);
|
||||
|
||||
$model = AssetModel::find($model_id);
|
||||
|
||||
self::handleCustomFields($model, $request, $asset);
|
||||
|
||||
$asset->save();
|
||||
if (request('assigned_user')) {
|
||||
$target = User::find(request('assigned_user'));
|
||||
// the api doesn't have these location-y bits - good reason?
|
||||
$location = $target->location_id;
|
||||
} elseif (request('assigned_asset')) {
|
||||
$target = Asset::find(request('assigned_asset'));
|
||||
$location = $target->location_id;
|
||||
} elseif (request('assigned_location')) {
|
||||
$target = Location::find(request('assigned_location'));
|
||||
$location = $target->id;
|
||||
}
|
||||
|
||||
if (isset($target)) {
|
||||
self::handleCheckout($target, $asset, $request, $location);
|
||||
}
|
||||
//this was in api and not gui
|
||||
if ($asset->image) {
|
||||
$asset->image = $asset->getImageUrl();
|
||||
}
|
||||
return $asset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $model
|
||||
* @param ImageUploadRequest $request
|
||||
* @param Asset|\App\Models\SnipeModel $asset
|
||||
* @return void
|
||||
*/
|
||||
private static function handleCustomFields($model, ImageUploadRequest $request, $asset): void
|
||||
{
|
||||
if (($model) && ($model instanceof AssetModel) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function handleImages($request, $asset)
|
||||
{
|
||||
//api
|
||||
if ($request->has('image_source')) {
|
||||
$request->offsetSet('image', $request->offsetGet('image_source'));
|
||||
}
|
||||
|
||||
if ($request->has('image')) {
|
||||
$asset = $request->handleImages($asset);
|
||||
}
|
||||
return $asset;
|
||||
}
|
||||
|
||||
private static function handleCheckout($target, $asset, $request, $location): void
|
||||
{
|
||||
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
|
||||
}
|
||||
}
|
259
app/Actions/Assets/UpdateAssetAction.php
Normal file
259
app/Actions/Assets/UpdateAssetAction.php
Normal file
|
@ -0,0 +1,259 @@
|
|||
<?php
|
||||
|
||||
namespace App\Actions\Assets;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Exceptions\CheckoutNotAllowed;
|
||||
use App\Exceptions\CustomFieldPermissionException;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\SnipeModel;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Watson\Validating\ValidationException;
|
||||
|
||||
class UpdateAssetAction
|
||||
{
|
||||
/**
|
||||
* @throws ValidationException
|
||||
* @throws CustomFieldPermissionException
|
||||
* @throws CheckoutNotAllowed
|
||||
*/
|
||||
public static function run(
|
||||
Asset $asset,
|
||||
ImageUploadRequest $request, //very much would like this to go away
|
||||
$status_id = null,
|
||||
$warranty_months = null,
|
||||
$purchase_cost = null,
|
||||
$purchase_date = null,
|
||||
$last_audit_date = null,
|
||||
$next_audit_date = null,
|
||||
$asset_eol_date = null,
|
||||
$supplier_id = null,
|
||||
$expected_checkin = null,
|
||||
$requestable = false,
|
||||
$location_id = null,
|
||||
$rtd_location_id = null,
|
||||
$assigned_location = null,
|
||||
$assigned_asset = null,
|
||||
$assigned_user = null,
|
||||
$byod = false,
|
||||
$image_delete = false,
|
||||
$serial = null,
|
||||
$name = null,
|
||||
$company_id = null,
|
||||
$model_id = null,
|
||||
$order_number = null,
|
||||
$asset_tag = null,
|
||||
$notes = null,
|
||||
$isBulk = false,
|
||||
): SnipeModel
|
||||
{
|
||||
|
||||
$asset->status_id = $status_id ?? $asset->status_id;
|
||||
$asset->warranty_months = $warranty_months ?? $asset->warranty_months;
|
||||
$asset->purchase_cost = $purchase_cost ?? $asset->purchase_cost;
|
||||
if ($request->input('null_purchase_date') === '1') {
|
||||
$asset->purchase_date = null;
|
||||
if (!($asset->eol_explicit)) {
|
||||
$asset->asset_eol_date = null;
|
||||
}
|
||||
} else {
|
||||
$asset->purchase_date = $purchase_date ?? $asset->purchase_date?->format('Y-m-d');
|
||||
}
|
||||
if ($request->input('null_next_audit_date') == '1') {
|
||||
$asset->next_audit_date = null;
|
||||
} else {
|
||||
$asset->next_audit_date = $next_audit_date ?? $asset->next_audit_date;
|
||||
}
|
||||
|
||||
$asset->last_audit_date = $last_audit_date ?? $asset->last_audit_date;
|
||||
if ($purchase_date && !$asset_eol_date && ($asset->model->eol > 0)) {
|
||||
$asset->purchase_date = $purchase_date ?? $asset->purchase_date?->format('Y-m-d');
|
||||
$asset->asset_eol_date = Carbon::parse($purchase_date)->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
$asset->eol_explicit = false;
|
||||
} elseif ($asset_eol_date) {
|
||||
$asset->asset_eol_date = $asset_eol_date ?? null;
|
||||
$months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
|
||||
if ($asset->model->eol) {
|
||||
if ($months != $asset->model->eol > 0) {
|
||||
$asset->eol_explicit = true;
|
||||
} else {
|
||||
$asset->eol_explicit = false;
|
||||
}
|
||||
} else {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
} elseif (!$asset_eol_date && (($asset->model->eol) == 0)) {
|
||||
$asset->asset_eol_date = null;
|
||||
$asset->eol_explicit = false;
|
||||
}
|
||||
$asset->supplier_id = $supplier_id;
|
||||
if ($request->input('null_expected_checkin_date') == '1') {
|
||||
$asset->expected_checkin = null;
|
||||
} else {
|
||||
$asset->expected_checkin = $expected_checkin ?? $asset->expected_checkin;
|
||||
}
|
||||
$asset->requestable = $requestable;
|
||||
|
||||
$asset->location_id = $location_id;
|
||||
|
||||
$asset->rtd_location_id = $rtd_location_id ?? $asset->rtd_location_id;
|
||||
if ($request->has('model_id')) {
|
||||
$asset->model()->associate(AssetModel::find($request->validated('model_id')));
|
||||
}
|
||||
if ($request->has('company_id')) {
|
||||
$asset->company_id = Company::getIdForCurrentUser($request->validated('company_id'));
|
||||
}
|
||||
if ($request->has('rtd_location_id') && !$request->has('location_id')) {
|
||||
$asset->location_id = $request->validated('rtd_location_id');
|
||||
}
|
||||
if ($request->input('last_audit_date')) {
|
||||
$asset->last_audit_date = Carbon::parse($request->input('last_audit_date'))->startOfDay()->format('Y-m-d H:i:s');
|
||||
}
|
||||
$asset->byod = $byod;
|
||||
|
||||
$status = Statuslabel::find($status_id);
|
||||
|
||||
// This is a non-deployable status label - we should check the asset back in.
|
||||
if (($status && $status->getStatuslabelType() != 'deployable') && ($target = $asset->assignedTo)) {
|
||||
$originalValues = $asset->getRawOriginal();
|
||||
$asset->assigned_to = null;
|
||||
$asset->assigned_type = null;
|
||||
$asset->accepted = null;
|
||||
|
||||
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update', date('Y-m-d H:i:s'), $originalValues));
|
||||
// reset this to null so checkout logic doesn't happen below
|
||||
$target = null;
|
||||
}
|
||||
|
||||
//this is causing an issue while setting location_id - this came from the gui but doesn't seem to work as expected in the api -
|
||||
//throwing on !expectsJson for now until we can work out how to handle this better
|
||||
if ($asset->assigned_to == '' && !$request->expectsJson()) {
|
||||
$asset->location_id = $rtd_location_id;
|
||||
}
|
||||
|
||||
|
||||
if ($image_delete) {
|
||||
try {
|
||||
unlink(public_path().'/uploads/assets/'.$asset->image);
|
||||
$asset->image = '';
|
||||
} catch (\Exception $e) {
|
||||
Log::info($e);
|
||||
}
|
||||
}
|
||||
|
||||
$asset->serial = $serial;
|
||||
|
||||
if ($request->filled('null_name')) {
|
||||
$asset->name = null;
|
||||
} else {
|
||||
$asset->name = $name ?? $asset->name;
|
||||
}
|
||||
$asset->company_id = Company::getIdForCurrentUser($company_id);
|
||||
$asset->model_id = $model_id ?? $asset->model_id;
|
||||
$asset->order_number = $order_number ?? $asset->order_number;
|
||||
|
||||
$asset->asset_tag = $asset_tag ?? $asset->asset_tag;
|
||||
|
||||
$asset->notes = $notes;
|
||||
|
||||
$asset = $request->handleImages($asset);
|
||||
|
||||
self::handleCustomFields($request, $asset);
|
||||
|
||||
if ($isBulk) {
|
||||
self::bulkLocationUpdate($asset, $request);
|
||||
}
|
||||
|
||||
$asset->save();
|
||||
// check out stuff
|
||||
$location = Location::find($asset->location_id);
|
||||
if (!is_null($assigned_user) && ($target = User::find($assigned_user))) {
|
||||
$location = $target->location_id;
|
||||
} elseif (!is_null($assigned_asset) && ($target = Asset::find($assigned_asset))) {
|
||||
$location = $target->location_id;
|
||||
Asset::where('assigned_type', \App\Models\Asset::class)->where('assigned_to', $asset->id)
|
||||
->update(['location_id' => $target->location_id]);
|
||||
} elseif (!is_null($assigned_location) && ($target = Location::find($assigned_location))) {
|
||||
$location = $target->id;
|
||||
}
|
||||
|
||||
if (isset($target)) {
|
||||
self::handleCheckout($asset, $target, $request, $location);
|
||||
}
|
||||
|
||||
if ($asset->image) {
|
||||
$asset->image = $asset->getImageUrl();
|
||||
}
|
||||
|
||||
return $asset;
|
||||
}
|
||||
|
||||
private static function bulkLocationUpdate($asset, $request): void
|
||||
{
|
||||
/**
|
||||
* We're changing the location ID - figure out which location we should apply
|
||||
* this change to:
|
||||
*
|
||||
* 0 - RTD location only
|
||||
* 1 - location ID and RTD location ID
|
||||
* 2 - location ID only
|
||||
*
|
||||
* Note: this is kinda dumb and we should just use human-readable values IMHO. - snipe
|
||||
*/
|
||||
if ($request->filled('rtd_location_id')) {
|
||||
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '0')) {
|
||||
$asset->rtd_location_id = $request->input('rtd_location_id');
|
||||
}
|
||||
|
||||
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '1')) {
|
||||
$asset->location_id = $request->input('rtd_location_id');
|
||||
$asset->rtd_location_id = $request->input('rtd_location_id');
|
||||
}
|
||||
|
||||
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '2')) {
|
||||
$asset->location_id = $request->input('rtd_location_id');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static function handleCustomFields($request, $asset): void
|
||||
{
|
||||
$model = $asset->model;
|
||||
if (($model) && (isset($model->fieldset))) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
$field_val = $request->input($field->db_column, null);
|
||||
|
||||
if ($request->has($field->db_column)) {
|
||||
if ($field->element == 'checkbox') {
|
||||
if (is_array($field_val)) {
|
||||
$field_val = implode(',', $field_val);
|
||||
}
|
||||
}
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')) {
|
||||
$field_val = Crypt::encrypt($field_val);
|
||||
} else {
|
||||
throw new CustomFieldPermissionException();
|
||||
}
|
||||
}
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function handleCheckout($asset, $target, $request, $location): void
|
||||
{
|
||||
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset update', e($request->get('name')), $location);
|
||||
}
|
||||
}
|
10
app/Exceptions/CustomFieldPermissionException.php
Normal file
10
app/Exceptions/CustomFieldPermissionException.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class CustomFieldPermissionException extends Exception
|
||||
{
|
||||
//
|
||||
}
|
|
@ -2,17 +2,21 @@
|
|||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Actions\Assets\DestroyAssetAction;
|
||||
use App\Actions\Assets\StoreAssetAction;
|
||||
use App\Actions\Assets\UpdateAssetAction;
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Http\Requests\StoreAssetRequest;
|
||||
use App\Http\Requests\UpdateAssetRequest;
|
||||
use App\Exceptions\CustomFieldPermissionException;
|
||||
use App\Exceptions\CheckoutNotAllowed;
|
||||
use App\Http\Requests\Assets\StoreAssetRequest;
|
||||
use App\Http\Requests\Assets\UpdateAssetRequest;
|
||||
use App\Http\Traits\MigratesLegacyAssetLocations;
|
||||
use App\Models\AccessoryCheckout;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\LicenseSeat;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AssetCheckoutRequest;
|
||||
|
@ -21,7 +25,6 @@ use App\Http\Transformers\LicensesTransformer;
|
|||
use App\Http\Transformers\SelectlistTransformer;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Company;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\License;
|
||||
use App\Models\Location;
|
||||
|
@ -32,6 +35,7 @@ use Illuminate\Support\Facades\DB;
|
|||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Watson\Validating\ValidationException;
|
||||
use App\View\Label;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
|
@ -127,7 +131,7 @@ class AssetsController extends Controller
|
|||
}
|
||||
|
||||
$assets = Asset::select('assets.*')
|
||||
->with(
|
||||
->with([
|
||||
'model',
|
||||
'location',
|
||||
'assetstatus',
|
||||
|
@ -140,7 +144,7 @@ class AssetsController extends Controller
|
|||
'model.manufacturer',
|
||||
'model.fieldset',
|
||||
'supplier'
|
||||
); // it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users.
|
||||
]); //it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users.
|
||||
|
||||
|
||||
if ($filter_non_deprecable_assets) {
|
||||
|
@ -602,87 +606,42 @@ class AssetsController extends Controller
|
|||
*/
|
||||
public function store(StoreAssetRequest $request): JsonResponse
|
||||
{
|
||||
$asset = new Asset();
|
||||
$asset->model()->associate(AssetModel::find((int) $request->get('model_id')));
|
||||
|
||||
$asset->fill($request->validated());
|
||||
$asset->created_by = auth()->id();
|
||||
|
||||
/**
|
||||
* this is here just legacy reasons. Api\AssetController
|
||||
* used image_source once to allow encoded image uploads.
|
||||
*/
|
||||
if ($request->has('image_source')) {
|
||||
$request->offsetSet('image', $request->offsetGet('image_source'));
|
||||
}
|
||||
|
||||
$asset = $request->handleImages($asset);
|
||||
|
||||
// Update custom fields in the database.
|
||||
$model = AssetModel::find($request->input('model_id'));
|
||||
|
||||
// Check that it's an object and not a collection
|
||||
// (Sometimes people send arrays here and they shouldn't
|
||||
if (($model) && ($model instanceof AssetModel) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
|
||||
// Set the field value based on what was sent in the request
|
||||
$field_val = $request->input($field->db_column, null);
|
||||
|
||||
// If input value is null, use custom field's default value
|
||||
if ($field_val == null) {
|
||||
Log::debug('Field value for ' . $field->db_column . ' is null');
|
||||
$field_val = $field->defaultValue($request->get('model_id'));
|
||||
Log::debug('Use the default fieldset value of ' . $field->defaultValue($request->get('model_id')));
|
||||
}
|
||||
|
||||
// if the field is set to encrypted, make sure we encrypt the value
|
||||
if ($field->field_encrypted == '1') {
|
||||
Log::debug('This model field is encrypted in this fieldset.');
|
||||
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')) {
|
||||
|
||||
// If input value is null, use custom field's default value
|
||||
if (($field_val == null) && ($request->has('model_id') != '')) {
|
||||
$field_val = Crypt::encrypt($field->defaultValue($request->get('model_id')));
|
||||
} else {
|
||||
$field_val = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($field->element == 'checkbox') {
|
||||
if (is_array($field_val)) {
|
||||
$field_val = implode(',', $field_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
}
|
||||
}
|
||||
|
||||
if ($asset->save()) {
|
||||
if ($request->get('assigned_user')) {
|
||||
$target = User::find(request('assigned_user'));
|
||||
} elseif ($request->get('assigned_asset')) {
|
||||
$target = Asset::find(request('assigned_asset'));
|
||||
} elseif ($request->get('assigned_location')) {
|
||||
$target = Location::find(request('assigned_location'));
|
||||
}
|
||||
if (isset($target)) {
|
||||
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset creation', e($request->get('name')));
|
||||
}
|
||||
|
||||
if ($asset->image) {
|
||||
$asset->image = $asset->getImageUrl();
|
||||
}
|
||||
|
||||
try {
|
||||
$asset = StoreAssetAction::run(
|
||||
model_id: $request->validated('model_id'),
|
||||
status_id: $request->validated('status_id'),
|
||||
request: $request, // this is for handleImages and custom fields
|
||||
name: $request->validated('name'),
|
||||
serial: $request->validated('serial'),
|
||||
company_id: $request->validated('company_id'),
|
||||
asset_tag: $request->validated('asset_tag'),
|
||||
order_number: $request->validated('order_number'),
|
||||
notes: $request->validated('notes'),
|
||||
warranty_months: $request->validated('warranty_months'),
|
||||
purchase_cost: $request->validated('purchase_cost'),
|
||||
asset_eol_date: $request->validated('asset_eol_date'),
|
||||
purchase_date: $request->validated('purchase_date'),
|
||||
assigned_to: $request->validated('assigned_to'),
|
||||
supplier_id: $request->validated('supplier_id'),
|
||||
requestable: $request->validated('requestable'),
|
||||
rtd_location_id: $request->validated('rtd_location_id'),
|
||||
location_id: $request->validated('location_id'),
|
||||
byod: $request->validated('byod'),
|
||||
assigned_user: $request->validated('assigned_user'),
|
||||
assigned_asset: $request->validated('assigned_asset'),
|
||||
assigned_location: $request->validated('assigned_location'),
|
||||
last_audit_date: $request->validated('last_audit_date'),
|
||||
);
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.create.success')));
|
||||
|
||||
// not sure why we're not using this yet, but i know there's a reason
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.create.success')));
|
||||
} catch (CheckoutNotAllowed $e) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $e->getMessage()), 200);
|
||||
} catch (Exception $e) {
|
||||
report($e);
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $e->getMessage()));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||
}
|
||||
|
||||
|
||||
|
@ -694,87 +653,19 @@ class AssetsController extends Controller
|
|||
*/
|
||||
public function update(UpdateAssetRequest $request, Asset $asset): JsonResponse
|
||||
{
|
||||
$asset->fill($request->validated());
|
||||
|
||||
if ($request->has('model_id')) {
|
||||
$asset->model()->associate(AssetModel::find($request->validated()['model_id']));
|
||||
try {
|
||||
$updatedAsset = UpdateAssetAction::run($asset, $request, ...$request->validated());
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
||||
} catch (CheckoutNotAllowed $e) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $e->getMessage()), 200);
|
||||
} catch (ValidationException $e) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $e->getErrors()), 200);
|
||||
} catch (CustomFieldPermissionException $e) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.encrypted_warning')));
|
||||
} catch (Exception $e) {
|
||||
report($e);
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.something_went_wrong')));
|
||||
}
|
||||
if ($request->has('company_id')) {
|
||||
$asset->company_id = Company::getIdForCurrentUser($request->validated()['company_id']);
|
||||
}
|
||||
if ($request->has('rtd_location_id') && !$request->has('location_id')) {
|
||||
$asset->location_id = $request->validated()['rtd_location_id'];
|
||||
}
|
||||
if ($request->input('last_audit_date')) {
|
||||
$asset->last_audit_date = Carbon::parse($request->input('last_audit_date'))->startOfDay()->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
/**
|
||||
* this is here just legacy reasons. Api\AssetController
|
||||
* used image_source once to allow encoded image uploads.
|
||||
*/
|
||||
if ($request->has('image_source')) {
|
||||
$request->offsetSet('image', $request->offsetGet('image_source'));
|
||||
}
|
||||
|
||||
$asset = $request->handleImages($asset);
|
||||
$model = $asset->model;
|
||||
|
||||
// Update custom fields
|
||||
$problems_updating_encrypted_custom_fields = false;
|
||||
if (($model) && (isset($model->fieldset))) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
$field_val = $request->input($field->db_column, null);
|
||||
|
||||
if ($request->has($field->db_column)) {
|
||||
if ($field->element == 'checkbox') {
|
||||
if (is_array($field_val)) {
|
||||
$field_val = implode(',', $field_val);
|
||||
}
|
||||
}
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')) {
|
||||
$field_val = Crypt::encrypt($field_val);
|
||||
} else {
|
||||
$problems_updating_encrypted_custom_fields = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$asset->{$field->db_column} = $field_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($asset->save()) {
|
||||
if (($request->filled('assigned_user')) && ($target = User::find($request->get('assigned_user')))) {
|
||||
$location = $target->location_id;
|
||||
} elseif (($request->filled('assigned_asset')) && ($target = Asset::find($request->get('assigned_asset')))) {
|
||||
$location = $target->location_id;
|
||||
|
||||
Asset::where('assigned_type', \App\Models\Asset::class)->where('assigned_to', $asset->id)
|
||||
->update(['location_id' => $target->location_id]);
|
||||
} elseif (($request->filled('assigned_location')) && ($target = Location::find($request->get('assigned_location')))) {
|
||||
$location = $target->id;
|
||||
}
|
||||
|
||||
if (isset($target)) {
|
||||
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset update', e($request->get('name')), $location);
|
||||
}
|
||||
|
||||
if ($asset->image) {
|
||||
$asset->image = $asset->getImageUrl();
|
||||
}
|
||||
|
||||
if ($problems_updating_encrypted_custom_fields) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.encrypted_warning')));
|
||||
// Below is the *correct* return since it uses the transformer, but we have to use the old, flat return for now until we can update Jamf2Snipe and Kanji2Snipe
|
||||
// return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.encrypted_warning')));
|
||||
} else {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success')));
|
||||
// Below is the *correct* return since it uses the transformer, but we have to use the old, flat return for now until we can update Jamf2Snipe and Kanji2Snipe
|
||||
/// return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.success')));
|
||||
}
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||
}
|
||||
|
||||
|
||||
|
@ -785,30 +676,16 @@ class AssetsController extends Controller
|
|||
* @param int $assetId
|
||||
* @since [v4.0]
|
||||
*/
|
||||
public function destroy($id): JsonResponse
|
||||
public function destroy(Asset $asset): JsonResponse
|
||||
{
|
||||
$this->authorize('delete', Asset::class);
|
||||
|
||||
if ($asset = Asset::find($id)) {
|
||||
$this->authorize('delete', $asset);
|
||||
|
||||
if ($asset->assignedTo) {
|
||||
|
||||
$target = $asset->assignedTo;
|
||||
$checkin_at = date('Y-m-d H:i:s');
|
||||
$originalValues = $asset->getRawOriginal();
|
||||
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on delete', $checkin_at, $originalValues));
|
||||
DB::table('assets')
|
||||
->where('id', $asset->id)
|
||||
->update(['assigned_to' => null]);
|
||||
}
|
||||
|
||||
$asset->delete();
|
||||
|
||||
$this->authorize('delete', $asset);
|
||||
try {
|
||||
DestroyAssetAction::run($asset);
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.delete.success')));
|
||||
} catch (Exception $e) {
|
||||
report($e);
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.something_went_wrong')));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1246,9 +1123,9 @@ class AssetsController extends Controller
|
|||
|
||||
/**
|
||||
* Generate asset labels by tag
|
||||
*
|
||||
*
|
||||
* @author [Nebelkreis] [https://github.com/NebelKreis]
|
||||
*
|
||||
*
|
||||
* @param Request $request Contains asset_tags array of asset tags to generate labels for
|
||||
* @return JsonResponse Returns base64 encoded PDF on success, error message on failure
|
||||
*/
|
||||
|
@ -1259,7 +1136,7 @@ class AssetsController extends Controller
|
|||
|
||||
// Validate that asset tags were provided in the request
|
||||
if (!$request->filled('asset_tags')) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null,
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null,
|
||||
trans('admin/hardware/message.no_assets_selected')), 400);
|
||||
}
|
||||
|
||||
|
@ -1282,7 +1159,7 @@ class AssetsController extends Controller
|
|||
|
||||
|
||||
$label = new Label();
|
||||
|
||||
|
||||
if (!$label) {
|
||||
throw new \Exception('Label object could not be created');
|
||||
}
|
||||
|
|
|
@ -2,35 +2,34 @@
|
|||
|
||||
namespace App\Http\Controllers\Assets;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Actions\Assets\DestroyAssetAction;
|
||||
use App\Actions\Assets\StoreAssetAction;
|
||||
use App\Actions\Assets\UpdateAssetAction;
|
||||
use App\Exceptions\CheckoutNotAllowed;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Requests\Assets\UpdateAssetRequest;
|
||||
use App\Http\Requests\Assets\StoreAssetRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\CheckoutRequest;
|
||||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use App\View\Label;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use League\Csv\Reader;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use TypeError;
|
||||
use Watson\Validating\ValidationException;
|
||||
|
||||
/**
|
||||
* This class controls all actions related to assets for
|
||||
|
@ -97,121 +96,51 @@ class AssetsController extends Controller
|
|||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function store(ImageUploadRequest $request) : RedirectResponse
|
||||
public function store(StoreAssetRequest $request): RedirectResponse
|
||||
{
|
||||
$this->authorize(Asset::class);
|
||||
|
||||
// There are a lot more rules to add here but prevents
|
||||
// errors around `asset_tags` not being present below.
|
||||
$this->validate($request, ['asset_tags' => ['required', 'array']]);
|
||||
|
||||
// Handle asset tags - there could be one, or potentially many.
|
||||
// This is only necessary on create, not update, since bulk editing is handled
|
||||
// differently
|
||||
$asset_tags = $request->input('asset_tags');
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
$successes = [];
|
||||
$failures = [];
|
||||
$errors = [];
|
||||
$asset_tags = $request->input('asset_tags');
|
||||
$serials = $request->input('serials');
|
||||
$asset = null;
|
||||
|
||||
for ($a = 1; $a <= count($asset_tags); $a++) {
|
||||
$asset = new Asset();
|
||||
$asset->model()->associate(AssetModel::find($request->input('model_id')));
|
||||
$asset->name = $request->input('name');
|
||||
|
||||
// Check for a corresponding serial
|
||||
if (($serials) && (array_key_exists($a, $serials))) {
|
||||
$asset->serial = $serials[$a];
|
||||
}
|
||||
|
||||
if (($asset_tags) && (array_key_exists($a, $asset_tags))) {
|
||||
$asset->asset_tag = $asset_tags[$a];
|
||||
}
|
||||
|
||||
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
||||
$asset->model_id = $request->input('model_id');
|
||||
$asset->order_number = $request->input('order_number');
|
||||
$asset->notes = $request->input('notes');
|
||||
$asset->created_by = auth()->id();
|
||||
$asset->status_id = request('status_id');
|
||||
$asset->warranty_months = request('warranty_months', null);
|
||||
$asset->purchase_cost = request('purchase_cost');
|
||||
$asset->purchase_date = request('purchase_date', null);
|
||||
$asset->asset_eol_date = request('asset_eol_date', null);
|
||||
$asset->assigned_to = request('assigned_to', null);
|
||||
$asset->supplier_id = request('supplier_id', null);
|
||||
$asset->requestable = request('requestable', 0);
|
||||
$asset->rtd_location_id = request('rtd_location_id', null);
|
||||
$asset->byod = request('byod', 0);
|
||||
|
||||
if (! empty($settings->audit_interval)) {
|
||||
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
||||
}
|
||||
|
||||
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
|
||||
if (!request('assigned_user') && !request('assigned_asset') && !request('assigned_location')) {
|
||||
$asset->location_id = $request->input('rtd_location_id', null);
|
||||
}
|
||||
|
||||
// Create the image (if one was chosen.)
|
||||
if ($request->has('image')) {
|
||||
$asset = $request->handleImages($asset);
|
||||
}
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handled through the AssetRequest form request
|
||||
$model = AssetModel::find($request->get('model_id'));
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the asset before saving
|
||||
if ($asset->isValid() && $asset->save()) {
|
||||
if (request('assigned_user')) {
|
||||
$target = User::find(request('assigned_user'));
|
||||
$location = $target->location_id;
|
||||
} elseif (request('assigned_asset')) {
|
||||
$target = Asset::find(request('assigned_asset'));
|
||||
$location = $target->location_id;
|
||||
} elseif (request('assigned_location')) {
|
||||
$target = Location::find(request('assigned_location'));
|
||||
$location = $target->id;
|
||||
}
|
||||
|
||||
if (isset($target)) {
|
||||
$asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
|
||||
}
|
||||
|
||||
$successes[] = "<a href='" . route('hardware.show', $asset) . "' style='color: white;'>" . e($asset->asset_tag) . "</a>";
|
||||
|
||||
} else {
|
||||
$failures[] = join(",", $asset->getErrors()->all());
|
||||
foreach ($asset_tags as $key => $asset_tag) {
|
||||
try {
|
||||
$asset = StoreAssetAction::run(
|
||||
model_id: $request->validated('model_id'),
|
||||
status_id: $request->validated('status_id'),
|
||||
request: $request,
|
||||
name: $request->validated('name'),
|
||||
serial: $request->has('serials') ? $serials[$key] : null,
|
||||
company_id: $request->validated('company_id'),
|
||||
asset_tag: $asset_tag,
|
||||
order_number: $request->validated('order_number'),
|
||||
notes: $request->validated('notes'),
|
||||
warranty_months: $request->validated('warranty_months'),
|
||||
purchase_cost: $request->validated('purchase_cost'),
|
||||
asset_eol_date: $request->validated('asset_eol_date'),
|
||||
purchase_date: $request->validated('purchase_date'),
|
||||
assigned_to: $request->validated('assigned_to'),
|
||||
supplier_id: $request->validated('supplier_id'),
|
||||
requestable: $request->validated('requestable'),
|
||||
rtd_location_id: $request->validated('rtd_location_id'),
|
||||
location_id: $request->validated('location_id'),
|
||||
byod: $request->validated('byod'),
|
||||
assigned_user: $request->validated('assigned_user'),
|
||||
assigned_asset: $request->validated('assigned_asset'),
|
||||
assigned_location: $request->validated('assigned_location'),
|
||||
last_audit_date: $request->validated('last_audit_date'),
|
||||
next_audit_date: $request->validated('next_audit_date'),
|
||||
);
|
||||
$successes[] = "<a href='".route('hardware.show', ['hardware' => $asset->id])."' style='color: white;'>".e($asset->asset_tag)."</a>";
|
||||
} catch (ValidationException|CheckoutNotAllowed $e) {
|
||||
$errors[] = $e->getMessage();
|
||||
} catch (Exception $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
$failures[] = join(",", $errors);
|
||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||
|
||||
|
||||
if ($successes) {
|
||||
if ($failures) {
|
||||
//some succeeded, some failed
|
||||
|
@ -230,13 +159,12 @@ class AssetsController extends Controller
|
|||
->with('success-unescaped', trans_choice('admin/hardware/message.create.multi_success_linked', $successes, ['links' => join(", ", $successes)]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->withErrors($asset->getErrors());
|
||||
// this shouldn't happen, but php complains if there's no final return
|
||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
||||
->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', $asset->id), 'id', 'tag' => e($asset->asset_tag)]));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a view that presents a form to edit an existing asset.
|
||||
*
|
||||
|
@ -302,127 +230,50 @@ class AssetsController extends Controller
|
|||
* @since [v1.0]
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*/
|
||||
public function update(ImageUploadRequest $request, Asset $asset) : RedirectResponse
|
||||
public function update(UpdateAssetRequest $request, Asset $asset): RedirectResponse
|
||||
{
|
||||
|
||||
$this->authorize($asset);
|
||||
|
||||
$asset->status_id = $request->input('status_id', null);
|
||||
$asset->warranty_months = $request->input('warranty_months', null);
|
||||
$asset->purchase_cost = $request->input('purchase_cost', null);
|
||||
$asset->purchase_date = $request->input('purchase_date', null);
|
||||
$asset->next_audit_date = $request->input('next_audit_date', null);
|
||||
if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && ($asset->model->eol > 0)) {
|
||||
$asset->purchase_date = $request->input('purchase_date', null);
|
||||
$asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
$asset->eol_explicit = false;
|
||||
} elseif ($request->filled('asset_eol_date')) {
|
||||
$asset->asset_eol_date = $request->input('asset_eol_date', null);
|
||||
$months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
|
||||
if($asset->model->eol) {
|
||||
if($months != $asset->model->eol > 0) {
|
||||
$asset->eol_explicit = true;
|
||||
} else {
|
||||
$asset->eol_explicit = false;
|
||||
}
|
||||
} else {
|
||||
$asset->eol_explicit = true;
|
||||
}
|
||||
} elseif (!$request->filled('asset_eol_date') && (($asset->model->eol) == 0)) {
|
||||
$asset->asset_eol_date = null;
|
||||
$asset->eol_explicit = false;
|
||||
}
|
||||
$asset->supplier_id = $request->input('supplier_id', null);
|
||||
$asset->expected_checkin = $request->input('expected_checkin', null);
|
||||
$asset->requestable = $request->input('requestable', 0);
|
||||
$asset->rtd_location_id = $request->input('rtd_location_id', null);
|
||||
$asset->byod = $request->input('byod', 0);
|
||||
|
||||
$status = Statuslabel::find($request->input('status_id'));
|
||||
|
||||
// This is an archived or undeployable - we should check the asset back in.
|
||||
// Pending is allowed here
|
||||
if (($status) && (($status->getStatuslabelType() != 'pending') && ($status->getStatuslabelType() != 'deployable')) && ($target = $asset->assignedTo)) {
|
||||
$originalValues = $asset->getRawOriginal();
|
||||
$asset->assigned_to = null;
|
||||
$asset->assigned_type = null;
|
||||
$asset->accepted = null;
|
||||
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update with '.$status->getStatuslabelType().' status', date('Y-m-d H:i:s'), $originalValues));
|
||||
}
|
||||
|
||||
if ($asset->assigned_to == '') {
|
||||
$asset->location_id = $request->input('rtd_location_id', null);
|
||||
}
|
||||
|
||||
|
||||
if ($request->filled('image_delete')) {
|
||||
try {
|
||||
unlink(public_path().'/uploads/assets/'.$asset->image);
|
||||
$asset->image = '';
|
||||
} catch (\Exception $e) {
|
||||
Log::info($e);
|
||||
try {
|
||||
$serial = $request->input('serials');
|
||||
$asset_tag = $request->input('asset_tags');
|
||||
if (is_array($request->input('serials'))) {
|
||||
$serial = $request->input('serials')[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Update the asset data
|
||||
|
||||
$serial = $request->input('serials');
|
||||
$asset->serial = $request->input('serials');
|
||||
|
||||
if (is_array($request->input('serials'))) {
|
||||
$asset->serial = $serial[1];
|
||||
}
|
||||
|
||||
$asset->name = $request->input('name');
|
||||
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
||||
$asset->model_id = $request->input('model_id');
|
||||
$asset->order_number = $request->input('order_number');
|
||||
|
||||
$asset_tags = $request->input('asset_tags');
|
||||
$asset->asset_tag = $request->input('asset_tags');
|
||||
|
||||
if (is_array($request->input('asset_tags'))) {
|
||||
$asset->asset_tag = $asset_tags[1];
|
||||
}
|
||||
|
||||
$asset->notes = $request->input('notes');
|
||||
|
||||
$asset = $request->handleImages($asset);
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handlded through the AssetRequest form request
|
||||
// FIXME: No idea why this is returning a Builder error on db_column_name.
|
||||
// Need to investigate and fix. Using static method for now.
|
||||
$model = AssetModel::find($request->get('model_id'));
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')) {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
|
||||
} else {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_array($request->input($field->db_column))) {
|
||||
$asset->{$field->db_column} = implode(', ', $request->input($field->db_column));
|
||||
} else {
|
||||
$asset->{$field->db_column} = $request->input($field->db_column);
|
||||
}
|
||||
}
|
||||
if (is_array($request->input('asset_tags'))) {
|
||||
$asset_tag = $request->input('asset_tags')[1];
|
||||
}
|
||||
}
|
||||
|
||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||
|
||||
if ($asset->save()) {
|
||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
||||
$updatedAsset = UpdateAssetAction::run(
|
||||
asset: $asset,
|
||||
request: $request,
|
||||
status_id: $request->validated('status_id'),
|
||||
warranty_months: $request->validated('warranty_months'),
|
||||
purchase_cost: $request->validated('purchase_cost'),
|
||||
purchase_date: $request->validated('purchase_date'),
|
||||
next_audit_date: $request->validated('next_audit_date'),
|
||||
asset_eol_date: $request->validated('asset_eol_date'),
|
||||
supplier_id: $request->validated('supplier_id'),
|
||||
expected_checkin: $request->validated('expected_checkin'),
|
||||
requestable: $request->validated('requestable'),
|
||||
rtd_location_id: $request->validated('rtd_location_id'),
|
||||
byod: $request->validated('byod'),
|
||||
image_delete: $request->validated('image_delete'),
|
||||
serial: $serial, // this needs to be set up in request somehow
|
||||
name: $request->validated('name'),
|
||||
company_id: $request->validated('company_id'),
|
||||
model_id: $request->validated('model_id'),
|
||||
order_number: $request->validated('order_number'),
|
||||
asset_tag: $asset_tag, // same as serials
|
||||
notes: $request->validated('notes'),
|
||||
);
|
||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
|
||||
return redirect()->to(Helper::getRedirectOption($request, $updatedAsset->id, 'Assets'))
|
||||
->with('success', trans('admin/hardware/message.update.success'));
|
||||
} catch (ValidationException $e) {
|
||||
return redirect()->back()->withInput()->withErrors($e->getErrors());
|
||||
} catch (Exception $e) {
|
||||
report($e);
|
||||
return redirect()->back()->with('error', trans('admin/hardware/message.update.error'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->withErrors($asset->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -432,39 +283,16 @@ class AssetsController extends Controller
|
|||
* @param int $assetId
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function destroy(Request $request, $assetId) : RedirectResponse
|
||||
public function destroy(Asset $asset): RedirectResponse
|
||||
{
|
||||
// Check if the asset exists
|
||||
if (is_null($asset = Asset::find($assetId))) {
|
||||
// Redirect to the asset management page with error
|
||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
|
||||
$this->authorize('delete', $asset);
|
||||
|
||||
if ($asset->assignedTo) {
|
||||
|
||||
$target = $asset->assignedTo;
|
||||
$checkin_at = date('Y-m-d H:i:s');
|
||||
$originalValues = $asset->getRawOriginal();
|
||||
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on delete', $checkin_at, $originalValues));
|
||||
DB::table('assets')
|
||||
->where('id', $asset->id)
|
||||
->update(['assigned_to' => null]);
|
||||
try {
|
||||
DestroyAssetAction::run($asset);
|
||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
|
||||
} catch (Exception $e) {
|
||||
report($e);
|
||||
return redirect()->back()->withInput()->withErrors($e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
if ($asset->image) {
|
||||
try {
|
||||
Storage::disk('public')->delete('assets'.'/'.$asset->image);
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
$asset->delete();
|
||||
|
||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -578,7 +406,7 @@ class AssetsController extends Controller
|
|||
file_put_contents($barcode_file, $barcode_obj->getPngData());
|
||||
|
||||
return response($barcode_obj->getPngData())->header('Content-type', 'image/png');
|
||||
} catch (\Exception|TypeError $e) {
|
||||
} catch (Exception $e) {
|
||||
Log::debug('The barcode format is invalid.');
|
||||
|
||||
return response(file_get_contents(public_path('uploads/barcodes/invalid_barcode.gif')))->header('Content-type', 'image/gif');
|
||||
|
@ -680,7 +508,7 @@ class AssetsController extends Controller
|
|||
$isCheckinHeaderExplicit = in_array('checkin date', (array_map('strtolower', $header)));
|
||||
try {
|
||||
$results = $csv->getRecords();
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
return back()->with('error', trans('general.error_in_import_file', ['error' => $e->getMessage()]));
|
||||
}
|
||||
$item = [];
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
namespace App\Http\Controllers\Assets;
|
||||
|
||||
use App\Actions\Assets\UpdateAssetAction;
|
||||
use App\Exceptions\CustomFieldPermissionException;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\CheckInOutRequest;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Statuslabel;
|
||||
|
@ -21,6 +24,7 @@ use App\Models\CustomField;
|
|||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Watson\Validating\ValidationException;
|
||||
|
||||
class BulkAssetsController extends Controller
|
||||
{
|
||||
|
@ -199,302 +203,59 @@ class BulkAssetsController extends Controller
|
|||
* @internal param array $assets
|
||||
* @since [v2.0]
|
||||
*/
|
||||
public function update(Request $request) : RedirectResponse
|
||||
public function update(ImageUploadRequest $request): RedirectResponse
|
||||
{
|
||||
// this should be in request, but request weird, need to think it through a little
|
||||
$this->authorize('update', Asset::class);
|
||||
$has_errors = 0;
|
||||
$error_array = array();
|
||||
|
||||
// Get the back url from the session and then destroy the session
|
||||
$bulk_back_url = route('hardware.index');
|
||||
|
||||
$custom_field_problem = false;
|
||||
// is this necessary?
|
||||
if (!$request->filled('ids') || count($request->input('ids')) == 0) {
|
||||
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
||||
}
|
||||
if ($request->session()->has('bulk_back_url')) {
|
||||
$bulk_back_url = $request->session()->pull('bulk_back_url');
|
||||
}
|
||||
|
||||
$custom_field_columns = CustomField::all()->pluck('db_column')->toArray();
|
||||
|
||||
|
||||
if (! $request->filled('ids') || count($request->input('ids')) == 0) {
|
||||
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
||||
}
|
||||
|
||||
|
||||
// find and update assets
|
||||
$assets = Asset::whereIn('id', $request->input('ids'))->get();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If ANY of these are filled, prepare to update the values on the assets.
|
||||
*
|
||||
* Additional checks will be needed for some of them to make sure the values
|
||||
* make sense (for example, changing the status ID to something incompatible with
|
||||
* its checkout status.
|
||||
*/
|
||||
|
||||
if (($request->filled('name'))
|
||||
|| ($request->filled('purchase_date'))
|
||||
|| ($request->filled('expected_checkin'))
|
||||
|| ($request->filled('purchase_cost'))
|
||||
|| ($request->filled('supplier_id'))
|
||||
|| ($request->filled('order_number'))
|
||||
|| ($request->filled('warranty_months'))
|
||||
|| ($request->filled('rtd_location_id'))
|
||||
|| ($request->filled('requestable'))
|
||||
|| ($request->filled('company_id'))
|
||||
|| ($request->filled('status_id'))
|
||||
|| ($request->filled('model_id'))
|
||||
|| ($request->filled('next_audit_date'))
|
||||
|| ($request->filled('asset_eol_date'))
|
||||
|| ($request->filled('null_name'))
|
||||
|| ($request->filled('null_purchase_date'))
|
||||
|| ($request->filled('null_expected_checkin_date'))
|
||||
|| ($request->filled('null_next_audit_date'))
|
||||
|| ($request->filled('null_asset_eol_date'))
|
||||
|| ($request->anyFilled($custom_field_columns))
|
||||
|
||||
) {
|
||||
// Let's loop through those assets and build an update array
|
||||
foreach ($assets as $asset) {
|
||||
|
||||
$this->update_array = [];
|
||||
|
||||
/**
|
||||
* Leave out model_id and status here because we do math on that later. We have to do some
|
||||
* extra validation and checks on those two.
|
||||
*
|
||||
* It's tempting to make these match the request check above, but some of these values require
|
||||
* extra work to make sure the data makes sense.
|
||||
*/
|
||||
$this->conditionallyAddItem('name')
|
||||
->conditionallyAddItem('purchase_date')
|
||||
->conditionallyAddItem('expected_checkin')
|
||||
->conditionallyAddItem('order_number')
|
||||
->conditionallyAddItem('requestable')
|
||||
->conditionallyAddItem('supplier_id')
|
||||
->conditionallyAddItem('warranty_months')
|
||||
->conditionallyAddItem('next_audit_date')
|
||||
->conditionallyAddItem('asset_eol_date');
|
||||
foreach ($custom_field_columns as $key => $custom_field_column) {
|
||||
$this->conditionallyAddItem($custom_field_column);
|
||||
}
|
||||
|
||||
if (!($asset->eol_explicit)) {
|
||||
if ($request->filled('model_id')) {
|
||||
$model = AssetModel::find($request->input('model_id'));
|
||||
if ($model->eol > 0) {
|
||||
if ($request->filled('purchase_date')) {
|
||||
$this->update_array['asset_eol_date'] = Carbon::parse($request->input('purchase_date'))->addMonths($model->eol)->format('Y-m-d');
|
||||
} else {
|
||||
$this->update_array['asset_eol_date'] = Carbon::parse($asset->purchase_date)->addMonths($model->eol)->format('Y-m-d');
|
||||
}
|
||||
} else {
|
||||
$this->update_array['asset_eol_date'] = null;
|
||||
}
|
||||
} elseif (($request->filled('purchase_date')) && ($asset->model->eol > 0)) {
|
||||
$this->update_array['asset_eol_date'] = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blank out fields that were requested to be blanked out via checkbox
|
||||
*/
|
||||
if ($request->input('null_name')=='1') {
|
||||
|
||||
$this->update_array['name'] = null;
|
||||
}
|
||||
|
||||
if ($request->input('null_purchase_date')=='1') {
|
||||
$this->update_array['purchase_date'] = null;
|
||||
if (!($asset->eol_explicit)) {
|
||||
$this->update_array['asset_eol_date'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->input('null_expected_checkin_date')=='1') {
|
||||
$this->update_array['expected_checkin'] = null;
|
||||
}
|
||||
|
||||
if ($request->input('null_next_audit_date')=='1') {
|
||||
$this->update_array['next_audit_date'] = null;
|
||||
}
|
||||
|
||||
if ($request->input('null_asset_eol_date')=='1') {
|
||||
$this->update_array['asset_eol_date'] = null;
|
||||
|
||||
// If they are nulling the EOL date to allow it to calculate, set eol explicit to 0
|
||||
if ($request->input('calc_eol')=='1') {
|
||||
$this->update_array['eol_explicit'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($request->filled('purchase_cost')) {
|
||||
$this->update_array['purchase_cost'] = $request->input('purchase_cost');
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$this->update_array['company_id'] = $request->input('company_id');
|
||||
if ($request->input('company_id') == 'clear') {
|
||||
$this->update_array['company_id'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We're trying to change the model ID - we need to do some extra checks here to make sure
|
||||
* the custom field values work for the custom fieldset rules around this asset. Uniqueness
|
||||
* and requiredness across the fieldset is particularly important, since those are
|
||||
* fieldset-specific attributes.
|
||||
*/
|
||||
if ($request->filled('model_id')) {
|
||||
$this->update_array['model_id'] = AssetModel::find($request->input('model_id'))->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* We're trying to change the status ID - we need to do some extra checks here to
|
||||
* make sure the status label type is one that makes sense for the state of the asset,
|
||||
* for example, we shouldn't be able to make an asset archived if it's currently assigned
|
||||
* to someone/something.
|
||||
*/
|
||||
if ($request->filled('status_id')) {
|
||||
try {
|
||||
$updated_status = Statuslabel::findOrFail($request->input('status_id'));
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return redirect($bulk_back_url)->with('error', trans('admin/statuslabels/message.does_not_exist'));
|
||||
}
|
||||
|
||||
// We cannot assign a non-deployable status type if the asset is already assigned.
|
||||
// This could probably be added to a form request.
|
||||
// If the asset isn't assigned, we don't care what the status is.
|
||||
// Otherwise we need to make sure the status type is still a deployable one.
|
||||
if (
|
||||
($asset->assigned_to == '')
|
||||
|| ($updated_status->deployable == '1') && ($asset->assetstatus?->deployable == '1')
|
||||
) {
|
||||
$this->update_array['status_id'] = $updated_status->id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* We're changing the location ID - figure out which location we should apply
|
||||
* this change to:
|
||||
*
|
||||
* 0 - RTD location only
|
||||
* 1 - location ID and RTD location ID
|
||||
* 2 - location ID only
|
||||
*
|
||||
* Note: this is kinda dumb and we should just use human-readable values IMHO. - snipe
|
||||
*/
|
||||
if ($request->filled('rtd_location_id')) {
|
||||
|
||||
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '0')) {
|
||||
$this->update_array['rtd_location_id'] = $request->input('rtd_location_id');
|
||||
}
|
||||
|
||||
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '1')) {
|
||||
$this->update_array['location_id'] = $request->input('rtd_location_id');
|
||||
$this->update_array['rtd_location_id'] = $request->input('rtd_location_id');
|
||||
}
|
||||
|
||||
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '2')) {
|
||||
$this->update_array['location_id'] = $request->input('rtd_location_id');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------------
|
||||
* ANYTHING that happens past this foreach
|
||||
* WILL NOT BE logged in the edit log_meta data
|
||||
* ------------------------------------------------------------------------------
|
||||
*/
|
||||
$changed = [];
|
||||
|
||||
foreach ($this->update_array as $key => $value) {
|
||||
|
||||
if ($this->update_array[$key] != $asset->{$key}) {
|
||||
$changed[$key]['old'] = $asset->{$key};
|
||||
$changed[$key]['new'] = $this->update_array[$key];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Start all the custom fields shenanigans
|
||||
*/
|
||||
|
||||
// Does the model have a fieldset?
|
||||
if ($asset->model->fieldset) {
|
||||
foreach ($asset->model->fieldset->fields as $field) {
|
||||
|
||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) {
|
||||
if (Gate::allows('admin')) {
|
||||
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
||||
|
||||
/*
|
||||
* Check if the decrypted existing value is different from one we just submitted
|
||||
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
||||
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
||||
* different times will have different values, so it will *look* like it was updated
|
||||
* but it wasn't.
|
||||
*/
|
||||
if ($decrypted_old != $this->update_array[$field->db_column]) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($this->update_array[$field->db_column]);
|
||||
} else {
|
||||
/*
|
||||
* Remove the encrypted custom field from the update_array, since nothing changed
|
||||
*/
|
||||
unset($this->update_array[$field->db_column]);
|
||||
unset($asset->{$field->db_column});
|
||||
}
|
||||
|
||||
/*
|
||||
* These custom fields aren't encrypted, just carry on as usual
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
|
||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) {
|
||||
|
||||
// Check if this is an array, and if so, flatten it
|
||||
if (is_array($this->update_array[$field->db_column])) {
|
||||
$asset->{$field->db_column} = implode(', ', $this->update_array[$field->db_column]);
|
||||
} else {
|
||||
$asset->{$field->db_column} = $this->update_array[$field->db_column];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // endforeach
|
||||
}
|
||||
|
||||
|
||||
// Check if it passes validation, and then try to save
|
||||
if (!$asset->update($this->update_array)) {
|
||||
|
||||
// Build the error array
|
||||
foreach ($asset->getErrors()->toArray() as $key => $message) {
|
||||
for ($x = 0; $x < count($message); $x++) {
|
||||
$error_array[$key][] = trans('general.asset') . ' ' . $asset->id . ': ' . $message[$x];
|
||||
$has_errors++;
|
||||
}
|
||||
}
|
||||
|
||||
} // end if saved
|
||||
|
||||
} // end asset foreach
|
||||
|
||||
if ($has_errors > 0) {
|
||||
return redirect($bulk_back_url)->with('bulk_asset_errors', $error_array);
|
||||
$errors = [];
|
||||
foreach ($assets as $key => $asset) {
|
||||
try {
|
||||
$updatedAsset = UpdateAssetAction::run(
|
||||
asset: $asset,
|
||||
request: $request,
|
||||
status_id: $request->input('status_id'),
|
||||
warranty_months: $request->input('warranty_months'),
|
||||
purchase_cost: $request->input('purchase_cost'),
|
||||
purchase_date: $request->filled('null_purchase_date') ? null : $request->input('purchase_date'),
|
||||
next_audit_date: $request->filled('null_next_audit_date') ? null : $request->input('next_audit_date'),
|
||||
supplier_id: $request->input('supplier_id'),
|
||||
expected_checkin: $request->filled('null_expected_checkin_date') ? null : $request->input('expected_checkin'),
|
||||
requestable: $request->input('requestable'),
|
||||
rtd_location_id: $request->input('rtd_location_id'),
|
||||
name: $request->filled('null_name') ? null : $request->input('name'),
|
||||
company_id: $request->input('company_id'),
|
||||
model_id: $request->input('model_id'),
|
||||
order_number: $request->input('order_number'),
|
||||
isBulk: true,
|
||||
);
|
||||
} catch (ValidationException $e) {
|
||||
$errors = $e->validator->errors()->toArray();
|
||||
} catch (CustomFieldPermissionException $e) {
|
||||
$custom_field_problem = true;
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$errors[$key] = [trans('general.something_went_wrong')];
|
||||
}
|
||||
|
||||
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.update.success'));
|
||||
}
|
||||
// no values given, nothing to update
|
||||
return redirect($bulk_back_url)->with('warning', trans('admin/hardware/message.update.nothing_updated'));
|
||||
if (!empty($errors)) {
|
||||
return redirect($bulk_back_url)->with('bulk_asset_errors', $errors);
|
||||
}
|
||||
if ($custom_field_problem) {
|
||||
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.encrypted_warning'));
|
||||
}
|
||||
return redirect($bulk_back_url)->with('success', trans('bulk.update.success'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
29
app/Http/Requests/Assets/DestroyAssetRequest.php
Normal file
29
app/Http/Requests/Assets/DestroyAssetRequest.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Assets;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class DestroyAssetRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::allows('delete', $this->asset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
namespace App\Http\Requests\Assets;
|
||||
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Requests\Traits\MayContainCustomFields;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
|
@ -36,8 +37,10 @@ class StoreAssetRequest extends ImageUploadRequest
|
|||
|
||||
$this->parseLastAuditDate();
|
||||
|
||||
$asset_tag = $this->parseAssetTag();
|
||||
|
||||
$this->merge([
|
||||
'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(),
|
||||
'asset_tag' => $asset_tag,
|
||||
'company_id' => $idForCurrentUser,
|
||||
'assigned_to' => $assigned_to ?? null,
|
||||
]);
|
||||
|
@ -60,7 +63,6 @@ class StoreAssetRequest extends ImageUploadRequest
|
|||
// converted to a float via setPurchaseCostAttribute).
|
||||
$modelRules = $this->removeNumericRulesFromPurchaseCost($modelRules);
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
$modelRules,
|
||||
['status_id' => [new AssetCannotBeCheckedOutToNondeployableStatus()]],
|
||||
|
@ -100,4 +102,14 @@ class StoreAssetRequest extends ImageUploadRequest
|
|||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
private function parseAssetTag(): mixed
|
||||
{
|
||||
// this is for a gui request to make the request pass validation
|
||||
// this just checks the first asset tag from the gui, watson should pick up if any of the rest of them fail
|
||||
if ($this->has('asset_tags') && !$this->expectsJson()) {
|
||||
return $this->input('asset_tags')[1];
|
||||
}
|
||||
return $this->asset_tag ?? Asset::autoincrement_asset();
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
namespace App\Http\Requests\Assets;
|
||||
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Requests\Traits\MayContainCustomFields;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
|
@ -28,11 +29,21 @@ class UpdateAssetRequest extends ImageUploadRequest
|
|||
*/
|
||||
public function rules()
|
||||
{
|
||||
$modelRules = (new Asset)->getRules();
|
||||
if ((Setting::getSettings()->digit_separator === '1.234,56' || '1,234.56') && is_string($this->input('purchase_cost'))) {
|
||||
// If purchase_cost was submitted as a string with a comma separator
|
||||
// then we need to ignore the normal numeric rules.
|
||||
// Since the original rules still live on the model they will be run
|
||||
// right before saving (and after purchase_cost has been
|
||||
// converted to a float via setPurchaseCostAttribute).
|
||||
$modelRules = $this->removeNumericRulesFromPurchaseCost($modelRules);
|
||||
}
|
||||
$rules = array_merge(
|
||||
parent::rules(),
|
||||
(new Asset)->getRules(),
|
||||
$modelRules,
|
||||
// this is to overwrite rulesets that include required, and rewrite unique_undeleted
|
||||
[
|
||||
'image_delete' => ['bool'],
|
||||
'model_id' => ['integer', 'exists:models,id,deleted_at,NULL', 'not_array'],
|
||||
'status_id' => ['integer', 'exists:status_labels,id'],
|
||||
'asset_tag' => [
|
||||
|
@ -47,6 +58,21 @@ class UpdateAssetRequest extends ImageUploadRequest
|
|||
if (Setting::getSettings()->digit_separator === '1.234,56' && is_string($this->input('purchase_cost'))) {
|
||||
$rules['purchase_cost'] = ['nullable', 'string'];
|
||||
}
|
||||
return $rules;
|
||||
}
|
||||
|
||||
private function removeNumericRulesFromPurchaseCost(array $rules): array
|
||||
{
|
||||
$purchaseCost = $rules['purchase_cost'];
|
||||
|
||||
// If rule is in "|" format then turn it into an array
|
||||
if (is_string($purchaseCost)) {
|
||||
$purchaseCost = explode('|', $purchaseCost);
|
||||
}
|
||||
|
||||
$rules['purchase_cost'] = array_filter($purchaseCost, function ($rule) {
|
||||
return $rule !== 'numeric' && $rule !== 'gte:0';
|
||||
});
|
||||
|
||||
return $rules;
|
||||
}
|
|
@ -7,6 +7,7 @@ use App\Models\Statuslabel;
|
|||
use App\Models\User;
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Watson\Validating\ValidationException;
|
||||
|
||||
class AssetImporter extends ItemImporter
|
||||
{
|
||||
|
@ -172,26 +173,30 @@ class AssetImporter extends ItemImporter
|
|||
// This sets an attribute on the Loggable trait for the action log
|
||||
$asset->setImported(true);
|
||||
|
||||
if ($asset->save()) {
|
||||
|
||||
try {
|
||||
$asset->save();
|
||||
$this->log('Asset '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
||||
|
||||
// If we have a target to checkout to, lets do so.
|
||||
//-- created_by is a property of the abstract class Importer, which this class inherits from and it's set by
|
||||
//-- the class that needs to use it (command importer or GUI importer inside the project).
|
||||
if (isset($target) && ($target !== false)) {
|
||||
if (!is_null($asset->assigned_to)){
|
||||
if (!is_null($asset->assigned_to)) {
|
||||
if ($asset->assigned_to != $target->id) {
|
||||
event(new CheckoutableCheckedIn($asset, User::find($asset->assigned_to), auth()->user(), 'Checkin from CSV Importer', $checkin_date));
|
||||
}
|
||||
}
|
||||
|
||||
$asset->fresh()->checkOut($target, $this->created_by, $checkout_date, null, 'Checkout from CSV Importer', $asset->name);
|
||||
$asset->fresh()->checkOut($target, $this->created_by, $checkout_date, null, 'Checkout from CSV Importer', $asset->name);
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (ValidationException $e) {
|
||||
$this->logError($asset, 'Asset "'.$this->item['name'].'"');
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$this->logError($asset, trans('general.something_went_wrong'));
|
||||
}
|
||||
$this->logError($asset, 'Asset "'.$this->item['name'].'"');
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ class Asset extends Depreciable
|
|||
use CompanyableTrait;
|
||||
use HasFactory, Loggable, Requestable, Presentable, SoftDeletes, ValidatingTrait, UniqueUndeletedTrait;
|
||||
|
||||
protected $throwValidationExceptions = true;
|
||||
|
||||
public const LOCATION = 'location';
|
||||
public const ASSET = 'asset';
|
||||
public const USER = 'user';
|
||||
|
|
|
@ -107,7 +107,7 @@ class UserFactory extends Factory
|
|||
return User::where('permissions->superuser', '1')->first() ?? User::factory()->firstAdmin();
|
||||
},
|
||||
];
|
||||
});
|
||||
})->appendPermission(['assets.view.encrypted_custom_fields' => '1']);
|
||||
}
|
||||
|
||||
public function viewAssets()
|
||||
|
|
|
@ -16,9 +16,9 @@ return [
|
|||
'create' => [
|
||||
'error' => 'Asset was not created, please try again. :(',
|
||||
'success' => 'Asset created successfully. :)',
|
||||
'success_linked' => 'Asset with tag :tag was created successfully. <strong><a href=":link" style="color: white;">Click here to view</a></strong>.',
|
||||
'success_linked' => 'Asset with tag :tag was created successfully. <strong><a href=":link" style="color: white;">Click here to view</a></strong>.',
|
||||
'multi_success_linked' => 'Asset with tag :links was created successfully.|:count assets were created succesfully. :links.',
|
||||
'partial_failure' => 'An asset was unable to be created. Reason: :failures|:count assets were unable to be created. Reasons: :failures',
|
||||
'partial_failure' => 'An asset was unable to be created. Reason: :failures|:count assets were unable to be created. Reasons: :failures',
|
||||
],
|
||||
|
||||
'update' => [
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
<i class="fas fa-exclamation-triangle faa-pulse animated"></i>
|
||||
<strong>{{ trans('general.notification_error') }}: </strong>
|
||||
{{ trans('general.notification_bulk_error_hint') }}
|
||||
@foreach($messages as $key => $message)
|
||||
@foreach($messages as $key => $message)
|
||||
@for ($x = 0; $x < count($message); $x++)
|
||||
<ul>
|
||||
<li>{{ $message[$x] }}</li>
|
||||
|
|
|
@ -596,15 +596,16 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'throttle:api']], functi
|
|||
|
||||
Route::put('/hardware/{asset}', [Api\AssetsController::class, 'update'])->name('api.assets.put-update');
|
||||
|
||||
Route::delete('/hardware/{asset}', [Api\AssetsController::class, 'destroy'])->name('api.assets.destroy');
|
||||
|
||||
Route::resource('hardware',
|
||||
Api\AssetsController::class,
|
||||
['names' => [
|
||||
'index' => 'api.assets.index',
|
||||
'show' => 'api.assets.show',
|
||||
'store' => 'api.assets.store',
|
||||
'destroy' => 'api.assets.destroy',
|
||||
],
|
||||
'except' => ['create', 'edit', 'update'],
|
||||
'except' => ['create', 'edit', 'update', 'destroy'],
|
||||
'parameters' => ['asset' => 'asset_id'],
|
||||
]
|
||||
); // end assets API routes
|
||||
|
|
|
@ -211,7 +211,7 @@ class BulkEditAssetsTest extends TestCase
|
|||
|
||||
$id_array = $assets->pluck('id')->toArray();
|
||||
|
||||
$this->actingAs(User::factory()->admin()->create())->post(route('hardware/bulksave'), [
|
||||
$this->actingAs(User::factory()->superuser()->create())->post(route('hardware/bulksave'), [
|
||||
'ids' => $id_array,
|
||||
$encrypted->db_column => 'New Encrypted Text',
|
||||
])->assertStatus(302);
|
||||
|
@ -221,7 +221,7 @@ class BulkEditAssetsTest extends TestCase
|
|||
});
|
||||
}
|
||||
|
||||
public function testBulkEditAssetsRequiresadminToUpdateEncryptedCustomFields()
|
||||
public function testBulkEditAssetsRequiresAdminToUpdateEncryptedCustomFields()
|
||||
{
|
||||
$this->markIncompleteIfMySQL('Custom Fields tests do not work on mysql');
|
||||
$edit_user = User::factory()->editAssets()->create();
|
||||
|
|
35
tests/Feature/Assets/Ui/DeleteAssetTest.php
Normal file
35
tests/Feature/Assets/Ui/DeleteAssetTest.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Assets\Ui;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DeleteAssetTest extends TestCase
|
||||
{
|
||||
public function test_asset_can_be_deleted_with_permissions()
|
||||
{
|
||||
$user = User::factory()->deleteAssets()->create();
|
||||
|
||||
$asset = Asset::factory()->create();
|
||||
$this->actingAs($user)
|
||||
->delete(route('hardware.destroy', $asset))
|
||||
->assertRedirect(route('hardware.index'));
|
||||
|
||||
$this->assertSoftDeleted($asset);
|
||||
}
|
||||
|
||||
public function test_asset_cannot_be_deleted_without_permissions()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$asset = Asset::factory()->create();
|
||||
$this->actingAs($user)
|
||||
->delete(route('hardware.destroy', $asset))
|
||||
->assertForbidden();
|
||||
|
||||
$this->assertModelExists($asset);
|
||||
}
|
||||
|
||||
}
|
|
@ -68,13 +68,26 @@ class EditAssetTest extends TestCase
|
|||
$this->assertDatabaseHas('assets', ['asset_tag' => 'New Asset Tag']);
|
||||
}
|
||||
|
||||
public function test_user_without_permission_is_denied()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$asset = Asset::factory()->create();
|
||||
|
||||
$this->actingAs($user)->put(route('hardware.update', $asset), [
|
||||
'name' => 'New name',
|
||||
'asset_tags' => 'New Asset Tag',
|
||||
'status_id' => StatusLabel::factory()->create()->id,
|
||||
'model_id' => AssetModel::factory()->create()->id,
|
||||
])->assertForbidden();
|
||||
}
|
||||
|
||||
public function testNewCheckinIsLoggedIfStatusChangedToUndeployable()
|
||||
{
|
||||
Event::fake([CheckoutableCheckedIn::class]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
$deployable_status = Statuslabel::factory()->rtd()->create();
|
||||
$achived_status = Statuslabel::factory()->archived()->create();
|
||||
$archived_status = Statuslabel::factory()->archived()->create();
|
||||
$asset = Asset::factory()->assignedToUser($user)->create(['status_id' => $deployable_status->id]);
|
||||
$this->assertTrue($asset->assignedTo->is($user));
|
||||
|
||||
|
@ -83,9 +96,9 @@ class EditAssetTest extends TestCase
|
|||
$this->actingAs(User::factory()->viewAssets()->editAssets()->create())
|
||||
->from(route('hardware.edit', $asset))
|
||||
->put(route('hardware.update', $asset), [
|
||||
'status_id' => $achived_status->id,
|
||||
'model_id' => $asset->model_id,
|
||||
'asset_tags' => $asset->asset_tag,
|
||||
'status_id' => $archived_status->id,
|
||||
'model_id' => $asset->model_id,
|
||||
'asset_tags' => $asset->asset_tag,
|
||||
],
|
||||
)
|
||||
->assertStatus(302);
|
||||
|
@ -95,7 +108,7 @@ class EditAssetTest extends TestCase
|
|||
$asset = Asset::find($asset->id);
|
||||
$this->assertNull($asset->assigned_to);
|
||||
$this->assertNull($asset->assigned_type);
|
||||
$this->assertEquals($achived_status->id, $asset->status_id);
|
||||
$this->assertEquals($archived_status->id, $asset->status_id);
|
||||
|
||||
Event::assertDispatched(function (CheckoutableCheckedIn $event) use ($currentTimestamp) {
|
||||
return Carbon::parse($event->action_date)->diffInSeconds($currentTimestamp) < 2;
|
||||
|
|
148
tests/Feature/Assets/Ui/StoreAssetTest.php
Normal file
148
tests/Feature/Assets/Ui/StoreAssetTest.php
Normal file
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Assets\Ui;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Location;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
class StoreAssetTest extends TestCase
|
||||
{
|
||||
public function test_all_fields_are_saved()
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$user = User::factory()->createAssets()->create();
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->readyToDeploy()->create();
|
||||
$defaultLocation = Location::factory()->create();
|
||||
$supplier = Supplier::factory()->create();
|
||||
$file = UploadedFile::fake()->image("test.jpg", 2000);
|
||||
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->post(route('hardware.store'), [
|
||||
'redirect_option' => 'item',
|
||||
'name' => 'Test Asset',
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
// ugh, this is because for some reason asset tags and serials are expected to start at an index of [1], so throwing an empty in for [0]
|
||||
'asset_tags' => ['', 'TEST-ASSET'],
|
||||
'serials' => ['', 'TEST-SERIAL'],
|
||||
'notes' => 'Test Notes',
|
||||
'rtd_location_id' => $defaultLocation->id,
|
||||
'requestable' => true,
|
||||
'image' => $file,
|
||||
'warranty_months' => 12,
|
||||
'next_audit_date' => Carbon::now()->addMonths(12)->format('Y-m-d'),
|
||||
'byod' => true,
|
||||
'order_number' => 'TEST-ORDER',
|
||||
'purchase_date' => Carbon::now()->format('Y-m-d'),
|
||||
'asset_eol_date' => Carbon::now()->addMonths(36)->format('Y-m-d'),
|
||||
'supplier_id' => $supplier->id,
|
||||
'purchase_cost' => 1234.56,
|
||||
])->assertSessionHasNoErrors();
|
||||
|
||||
$storedAsset = Asset::where('asset_tag', 'TEST-ASSET')->sole();
|
||||
|
||||
$response->assertRedirect(route('hardware.show', $storedAsset));
|
||||
|
||||
$this->assertDatabaseHas('assets', [
|
||||
'id' => $storedAsset->id,
|
||||
'name' => 'Test Asset',
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'asset_tag' => 'TEST-ASSET',
|
||||
'serial' => 'TEST-SERIAL',
|
||||
'notes' => 'Test Notes',
|
||||
'rtd_location_id' => $defaultLocation->id,
|
||||
'requestable' => 1,
|
||||
'image' => $storedAsset->image,
|
||||
'warranty_months' => 12,
|
||||
'next_audit_date' => Carbon::now()->addMonths(12)->format('Y-m-d'),
|
||||
'byod' => 1,
|
||||
'order_number' => 'TEST-ORDER',
|
||||
'purchase_date' => Carbon::now()->format('Y-m-d'),
|
||||
'asset_eol_date' => Carbon::now()->addMonths(36)->format('Y-m-d'),
|
||||
'supplier_id' => $supplier->id,
|
||||
'purchase_cost' => 1234.56,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_multiple_assets_are_stored()
|
||||
{
|
||||
$user = User::factory()->createAssets()->create();
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->readyToDeploy()->create();
|
||||
$defaultLocation = Location::factory()->create();
|
||||
$supplier = Supplier::factory()->create();
|
||||
$file = UploadedFile::fake()->image("test.jpg", 2000);
|
||||
|
||||
$this->actingAs($user)->post(route('hardware.store'), [
|
||||
'redirect_option' => 'index',
|
||||
'name' => 'Test Assets',
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'asset_tags' => ['', 'TEST-ASSET-1', 'TEST-ASSET-2'],
|
||||
'serials' => ['', 'TEST-SERIAL-1', 'TEST-SERIAL-2'],
|
||||
'notes' => 'Test Notes',
|
||||
'rtd_location_id' => $defaultLocation->id,
|
||||
'requestable' => true,
|
||||
'image' => $file,
|
||||
'warranty_months' => 12,
|
||||
'next_audit_date' => Carbon::now()->addMonths(12)->format('Y-m-d'),
|
||||
'byod' => true,
|
||||
'order_number' => 'TEST-ORDER',
|
||||
'purchase_date' => Carbon::now()->format('Y-m-d'),
|
||||
'asset_eol_date' => Carbon::now()->addMonths(36)->format('Y-m-d'),
|
||||
'supplier_id' => $supplier->id,
|
||||
'purchase_cost' => 1234.56,
|
||||
])->assertRedirect(route('hardware.index'))->assertSessionHasNoErrors();
|
||||
|
||||
$storedAsset = Asset::where('asset_tag', 'TEST-ASSET-1')->sole();
|
||||
$storedAsset2 = Asset::where('asset_tag', 'TEST-ASSET-2')->sole();
|
||||
|
||||
$commonData = [
|
||||
'name' => 'Test Assets',
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'notes' => 'Test Notes',
|
||||
'rtd_location_id' => $defaultLocation->id,
|
||||
'requestable' => 1,
|
||||
'warranty_months' => 12,
|
||||
'next_audit_date' => Carbon::now()->addMonths(12)->format('Y-m-d'),
|
||||
'byod' => 1,
|
||||
'order_number' => 'TEST-ORDER',
|
||||
'purchase_date' => Carbon::now()->format('Y-m-d'),
|
||||
'asset_eol_date' => Carbon::now()->addMonths(36)->format('Y-m-d'),
|
||||
'supplier_id' => $supplier->id,
|
||||
'purchase_cost' => 1234.56,
|
||||
];
|
||||
|
||||
$this->assertDatabaseHas('assets', array_merge($commonData, ['asset_tag' => 'TEST-ASSET-1', 'serial' => 'TEST-SERIAL-1', 'image' => $storedAsset->image]));
|
||||
$this->assertDatabaseHas('assets', array_merge($commonData, ['asset_tag' => 'TEST-ASSET-2', 'serial' => 'TEST-SERIAL-2', 'image' => $storedAsset2->image]));
|
||||
}
|
||||
|
||||
public function test_user_without_permission_denied()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->readyToDeploy()->create();
|
||||
|
||||
$this->actingAs($user)->post(route('hardware.store'), [
|
||||
'redirect_option' => 'index',
|
||||
'name' => 'Test Assets',
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'asset_tags' => ['', 'TEST-ASSET-1'],
|
||||
'serials' => ['', 'TEST-SERIAL-1'],
|
||||
])->assertForbidden();
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ use App\Models\Category;
|
|||
use Carbon\Carbon;
|
||||
use Tests\TestCase;
|
||||
use App\Models\Setting;
|
||||
use Watson\Validating\ValidationException;
|
||||
|
||||
class AssetTest extends TestCase
|
||||
{
|
||||
|
@ -31,7 +32,8 @@ class AssetTest extends TestCase
|
|||
$b = Asset::factory()->make(['asset_tag' => Asset::autoincrement_asset() ]);
|
||||
|
||||
$this->assertTrue($a->save());
|
||||
$this->assertFalse($b->save());
|
||||
$this->expectException(ValidationException::class);
|
||||
$b->save();
|
||||
}
|
||||
|
||||
public function testAutoIncrementDouble()
|
||||
|
@ -181,7 +183,7 @@ class AssetTest extends TestCase
|
|||
]
|
||||
)->id,
|
||||
'warranty_months' => 24,
|
||||
'purchase_date' => Carbon::createFromDate(2017, 1, 1)->hour(0)->minute(0)->second(0)
|
||||
'purchase_date' => Carbon::createFromDate(2017, 1, 1)->hour(0)->minute(0)->second(0)->format("Y-m-d")
|
||||
]);
|
||||
|
||||
|
||||
|
|
|
@ -38,8 +38,7 @@ class DepreciationTest extends TestCase
|
|||
->laptopMbp()
|
||||
->create(
|
||||
[
|
||||
'category_id' => Category::factory()->assetLaptopCategory()->create(),
|
||||
'purchase_date' => now()->subDecade(),
|
||||
'purchase_date' => now()->subDecade()->format("Y-m-d"),
|
||||
'purchase_cost' => 4000,
|
||||
]);
|
||||
$asset->model->update([
|
||||
|
@ -62,8 +61,7 @@ class DepreciationTest extends TestCase
|
|||
->laptopMbp()
|
||||
->create(
|
||||
[
|
||||
'category_id' => Category::factory()->assetLaptopCategory()->create(),
|
||||
'purchase_date' => now()->subDecade(),
|
||||
'purchase_date' => now()->subDecade()->format("Y-m-d"),
|
||||
'purchase_cost' => 4000,
|
||||
]);
|
||||
$asset->model->update([
|
||||
|
|
Loading…
Reference in a new issue