diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index 7c65e49bcd..1665b7f4f0 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Api; use App\Events\CheckoutableCheckedOut; use App\Helpers\Helper; use App\Http\Controllers\Controller; +use App\Http\Requests\StoreConsumableRequest; use App\Http\Transformers\ConsumablesTransformer; use App\Http\Transformers\SelectlistTransformer; use App\Models\Company; @@ -27,27 +28,8 @@ class ConsumablesController extends Controller { $this->authorize('index', Consumable::class); - // This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations - // Relations will be handled in query scopes a little further down. - $allowed_columns = - [ - 'id', - 'name', - 'order_number', - 'min_amt', - 'purchase_date', - 'purchase_cost', - 'company', - 'category', - 'model_number', - 'item_no', - 'qty', - 'image', - 'notes', - ]; - - $consumables = Consumable::select('consumables.*') - ->with('company', 'location', 'category', 'users', 'manufacturer'); + $consumables = Consumable::with('company', 'location', 'category', 'supplier', 'manufacturer') + ->withCount('users as consumables_users_count'); if ($request->filled('search')) { $consumables = $consumables->TextSearch(e($request->input('search'))); @@ -89,15 +71,9 @@ class ConsumablesController extends Controller // Make sure the offset and limit are actually integers and do not exceed system limits $offset = ($request->input('offset') > $consumables->count()) ? $consumables->count() : app('api_offset_value'); $limit = app('api_limit_value'); - - $allowed_columns = ['id', 'name', 'order_number', 'min_amt', 'purchase_date', 'purchase_cost', 'company', 'category', 'model_number', 'item_no', 'manufacturer', 'location', 'qty', 'image']; $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; - $sort_override = $request->input('sort'); - $column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'created_at'; - - - switch ($sort_override) { + switch ($request->input('sort')) { case 'category': $consumables = $consumables->OrderCategory($order); break; @@ -111,10 +87,30 @@ class ConsumablesController extends Controller $consumables = $consumables->OrderCompany($order); break; case 'supplier': - $components = $consumables->OrderSupplier($order); + $consumables = $consumables->OrderSupplier($order); break; default: - $consumables = $consumables->orderBy($column_sort, $order); + // This array is what determines which fields should be allowed to be sorted on ON the table itself. + // These must match a column on the consumables table directly. + $allowed_columns = [ + 'id', + 'name', + 'order_number', + 'min_amt', + 'purchase_date', + 'purchase_cost', + 'company', + 'category', + 'model_number', + 'item_no', + 'manufacturer', + 'location', + 'qty', + 'image' + ]; + + $sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at'; + $consumables = $consumables->orderBy($sort, $order); break; } @@ -131,7 +127,7 @@ class ConsumablesController extends Controller * @since [v4.0] * @param \App\Http\Requests\ImageUploadRequest $request */ - public function store(ImageUploadRequest $request) : JsonResponse + public function store(StoreConsumableRequest $request) : JsonResponse { $this->authorize('create', Consumable::class); $consumable = new Consumable; @@ -167,7 +163,7 @@ class ConsumablesController extends Controller * @param \App\Http\Requests\ImageUploadRequest $request * @param int $id */ - public function update(ImageUploadRequest $request, $id) : JsonResponse + public function update(StoreConsumableRequest $request, $id) : JsonResponse { $this->authorize('update', Consumable::class); $consumable = Consumable::findOrFail($id); diff --git a/app/Http/Controllers/Consumables/ConsumableCheckoutController.php b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php index 919cd1698f..fd690fede8 100644 --- a/app/Http/Controllers/Consumables/ConsumableCheckoutController.php +++ b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php @@ -4,12 +4,11 @@ namespace App\Http\Controllers\Consumables; use App\Events\CheckoutableCheckedOut; use App\Http\Controllers\Controller; -use App\Models\Accessory; use App\Models\Consumable; use App\Models\User; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; -use Illuminate\Support\Facades\Input; +use \Illuminate\Contracts\View\View; +use \Illuminate\Http\RedirectResponse; class ConsumableCheckoutController extends Controller { @@ -20,13 +19,11 @@ class ConsumableCheckoutController extends Controller * @see ConsumableCheckoutController::store() method that stores the data. * @since [v1.0] * @param int $id - * @return \Illuminate\Contracts\View\View - * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function create($id) + public function create($id) : View | RedirectResponse { - if ($consumable = Consumable::with('users')->find($id)) { + if ($consumable = Consumable::find($id)) { $this->authorize('checkout', $consumable); diff --git a/app/Http/Controllers/Consumables/ConsumablesController.php b/app/Http/Controllers/Consumables/ConsumablesController.php index b33e6e07a9..5685944a5c 100644 --- a/app/Http/Controllers/Consumables/ConsumablesController.php +++ b/app/Http/Controllers/Consumables/ConsumablesController.php @@ -8,8 +8,10 @@ use App\Http\Requests\ImageUploadRequest; use App\Models\Company; use App\Models\Consumable; use Illuminate\Support\Facades\Auth; -use Illuminate\Support\Facades\Input; use Illuminate\Support\Facades\Validator; +use Illuminate\Http\RedirectResponse; +use \Illuminate\Contracts\View\View; +use App\Http\Requests\StoreConsumableRequest; /** * This controller handles all actions related to Consumables for @@ -62,7 +64,7 @@ class ConsumablesController extends Controller * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function store(ImageUploadRequest $request) + public function store(StoreConsumableRequest $request) { $this->authorize('create', Consumable::class); $consumable = new Consumable(); @@ -99,10 +101,8 @@ class ConsumablesController extends Controller * @param int $consumableId * @see ConsumablesController::postEdit() method that stores the form data. * @since [v1.0] - * @return \Illuminate\Contracts\View\View - * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function edit($consumableId = null) + public function edit($consumableId = null) : View | RedirectResponse { if ($item = Consumable::find($consumableId)) { $this->authorize($item); @@ -124,7 +124,7 @@ class ConsumablesController extends Controller * @see ConsumablesController::getEdit() method that stores the form data. * @since [v1.0] */ - public function update(ImageUploadRequest $request, $consumableId = null) + public function update(StoreConsumableRequest $request, $consumableId = null) { if (is_null($consumable = Consumable::find($consumableId))) { return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist')); @@ -182,6 +182,7 @@ class ConsumablesController extends Controller return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found')); } $this->authorize($consumable); + $consumable->delete(); // Redirect to the locations management page return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.delete.success')); diff --git a/app/Http/Requests/StoreConsumableRequest.php b/app/Http/Requests/StoreConsumableRequest.php new file mode 100644 index 0000000000..9062b07cc5 --- /dev/null +++ b/app/Http/Requests/StoreConsumableRequest.php @@ -0,0 +1,56 @@ +category_id) { + if ($category = Category::find($this->category_id)) { + $this->merge([ + 'category_type' => $category->category_type ?? null, + ]); + } + } + + } + + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + return array_merge( + ['category_type' => 'in:consumable'], + parent::rules(), + ); + } + + public function messages(): array + { + $messages = ['category_type.in' => trans('admin/consumables/message.invalid_category_type')]; + return $messages; + } + + public function response(array $errors) + { + return $this->redirector->back()->withInput()->withErrors($errors, $this->errorBag); + } +} diff --git a/app/Models/Consumable.php b/app/Models/Consumable.php index 008dffa4ca..944ac5bfde 100644 --- a/app/Models/Consumable.php +++ b/app/Models/Consumable.php @@ -10,12 +10,21 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Storage; use Watson\Validating\ValidatingTrait; +use Illuminate\Database\Eloquent\Relations\Relation; +use App\Presenters\ConsumablePresenter; +use App\Models\Actionlog; +use App\Models\ConsumableAssignment; +use App\Models\User; +use App\Models\Location; +use App\Models\Manufacturer; +use App\Models\Supplier; +use App\Models\Category; class Consumable extends SnipeModel { use HasFactory; - protected $presenter = \App\Presenters\ConsumablePresenter::class; + protected $presenter = ConsumablePresenter::class; use CompanyableTrait; use Loggable, Presentable; use SoftDeletes; @@ -37,10 +46,10 @@ class Consumable extends SnipeModel */ public $rules = [ 'name' => 'required|min:3|max:255', - 'qty' => 'required|integer|min:0', + 'qty' => 'required|integer|min:0|max:99999', 'category_id' => 'required|integer', 'company_id' => 'integer|nullable', - 'min_amt' => 'integer|min:0|nullable', + 'min_amt' => 'integer|min:0|max:99999|nullable', 'purchase_cost' => 'numeric|nullable|gte:0', 'purchase_date' => 'date_format:Y-m-d|nullable', ]; @@ -109,7 +118,7 @@ class Consumable extends SnipeModel */ public function uploads() { - return $this->hasMany(\App\Models\Actionlog::class, 'item_id') + return $this->hasMany(Actionlog::class, 'item_id') ->where('item_type', '=', self::class) ->where('action_type', '=', 'uploaded') ->whereNotNull('filename') @@ -147,7 +156,7 @@ class Consumable extends SnipeModel */ public function admin() { - return $this->belongsTo(\App\Models\User::class, 'user_id'); + return $this->belongsTo(User::class, 'user_id'); } /** @@ -159,7 +168,7 @@ class Consumable extends SnipeModel */ public function consumableAssignments() { - return $this->hasMany(\App\Models\ConsumableAssignment::class); + return $this->hasMany(ConsumableAssignment::class); } /** @@ -183,7 +192,7 @@ class Consumable extends SnipeModel */ public function manufacturer() { - return $this->belongsTo(\App\Models\Manufacturer::class, 'manufacturer_id'); + return $this->belongsTo(Manufacturer::class, 'manufacturer_id'); } /** @@ -195,7 +204,7 @@ class Consumable extends SnipeModel */ public function location() { - return $this->belongsTo(\App\Models\Location::class, 'location_id'); + return $this->belongsTo(Location::class, 'location_id'); } /** @@ -207,7 +216,7 @@ class Consumable extends SnipeModel */ public function category() { - return $this->belongsTo(\App\Models\Category::class, 'category_id'); + return $this->belongsTo(Category::class, 'category_id'); } @@ -220,7 +229,7 @@ class Consumable extends SnipeModel */ public function assetlog() { - return $this->hasMany(\App\Models\Actionlog::class, 'item_id')->where('item_type', self::class)->orderBy('created_at', 'desc')->withTrashed(); + return $this->hasMany(Actionlog::class, 'item_id')->where('item_type', self::class)->orderBy('created_at', 'desc')->withTrashed(); } /** @@ -244,11 +253,10 @@ class Consumable extends SnipeModel * * @author [A. Gianotto] [] * @since [v3.0] - * @return \Illuminate\Database\Eloquent\Relations\Relation */ - public function users() + public function users() : Relation { - return $this->belongsToMany(\App\Models\User::class, 'consumables_users', 'consumable_id', 'assigned_to')->withPivot('user_id')->withTrashed()->withTimestamps(); + return $this->belongsToMany(User::class, 'consumables_users', 'consumable_id', 'assigned_to')->withPivot('user_id')->withTrashed()->withTimestamps(); } /** @@ -260,7 +268,7 @@ class Consumable extends SnipeModel */ public function supplier() { - return $this->belongsTo(\App\Models\Supplier::class, 'supplier_id'); + return $this->belongsTo(Supplier::class, 'supplier_id'); } @@ -317,10 +325,7 @@ class Consumable extends SnipeModel */ public function numCheckedOut() { - $checkedout = 0; - $checkedout = $this->users->count(); - - return $checkedout; + return $this->consumables_users_count ?? $this->users()->count(); } /** @@ -332,7 +337,7 @@ class Consumable extends SnipeModel */ public function numRemaining() { - $checkedout = $this->users->count(); + $checkedout = $this->numCheckedOut(); $total = $this->qty; $remaining = $total - $checkedout; diff --git a/app/Models/ConsumableAssignment.php b/app/Models/ConsumableAssignment.php index 1e21a7f7d2..db0cfa4bd6 100644 --- a/app/Models/ConsumableAssignment.php +++ b/app/Models/ConsumableAssignment.php @@ -3,13 +3,19 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Watson\Validating\ValidatingTrait; class ConsumableAssignment extends Model { use CompanyableTrait; + use ValidatingTrait; protected $table = 'consumables_users'; + public $rules = [ + 'assigned_to' => 'required|exists:users,id', + ]; + public function consumable() { return $this->belongsTo(\App\Models\Consumable::class); diff --git a/app/Observers/ConsumableObserver.php b/app/Observers/ConsumableObserver.php index 08c56d2ee2..377995ebb9 100644 --- a/app/Observers/ConsumableObserver.php +++ b/app/Observers/ConsumableObserver.php @@ -5,6 +5,8 @@ namespace App\Observers; use App\Models\Actionlog; use App\Models\Consumable; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Storage; class ConsumableObserver { @@ -16,12 +18,26 @@ class ConsumableObserver */ public function updated(Consumable $consumable) { - $logAction = new Actionlog(); - $logAction->item_type = Consumable::class; - $logAction->item_id = $consumable->id; - $logAction->created_at = date('Y-m-d H:i:s'); - $logAction->user_id = Auth::id(); - $logAction->logaction('update'); + + $changed = []; + + foreach ($consumable->getRawOriginal() as $key => $value) { + // Check and see if the value changed + if ($consumable->getRawOriginal()[$key] != $consumable->getAttributes()[$key]) { + $changed[$key]['old'] = $consumable->getRawOriginal()[$key]; + $changed[$key]['new'] = $consumable->getAttributes()[$key]; + } + } + + if (count($changed) > 0) { + $logAction = new Actionlog(); + $logAction->item_type = Consumable::class; + $logAction->item_id = $consumable->id; + $logAction->created_at = date('Y-m-d H:i:s'); + $logAction->user_id = Auth::id(); + $logAction->log_meta = json_encode($changed); + $logAction->logaction('update'); + } } /** @@ -52,6 +68,32 @@ class ConsumableObserver */ public function deleting(Consumable $consumable) { + + $consumable->users()->detach(); + $uploads = $consumable->uploads; + + foreach ($uploads as $file) { + try { + Storage::delete('private_uploads/consumables/'.$file->filename); + $file->delete(); + } catch (\Exception $e) { + Log::info($e); + } + } + + + + try { + Storage::disk('public')->delete('consumables/'.$consumable->image); + } catch (\Exception $e) { + Log::info($e); + } + + $consumable->image = null; + $consumable->save(); + + + $logAction = new Actionlog(); $logAction->item_type = Consumable::class; $logAction->item_id = $consumable->id; diff --git a/app/Presenters/ActionlogPresenter.php b/app/Presenters/ActionlogPresenter.php index 2794b6c5fb..ebbe3d7823 100644 --- a/app/Presenters/ActionlogPresenter.php +++ b/app/Presenters/ActionlogPresenter.php @@ -75,7 +75,7 @@ class ActionlogPresenter extends Presenter } if ($this->actionType()=='delete') { - return 'fa-solid fa-user-xmark'; + return 'fa-solid fa-trash'; } if ($this->actionType()=='update') { diff --git a/resources/lang/en-US/admin/consumables/message.php b/resources/lang/en-US/admin/consumables/message.php index c0d0aa7f68..e2591503bf 100644 --- a/resources/lang/en-US/admin/consumables/message.php +++ b/resources/lang/en-US/admin/consumables/message.php @@ -2,6 +2,7 @@ return array( + 'invalid_category_type' => 'The category must be a consumable category.', 'does_not_exist' => 'Consumable does not exist.', 'create' => array( diff --git a/resources/views/consumables/checkout.blade.php b/resources/views/consumables/checkout.blade.php index bde94bc6f4..29b68b6ce7 100644 --- a/resources/views/consumables/checkout.blade.php +++ b/resources/views/consumables/checkout.blade.php @@ -37,6 +37,25 @@ @endif + +
+ +
+

{{ $consumable->qty }}

+
+
+ + +
+ +
+

{{ $consumable->numRemaining() }}

+
+
+ + + + @include ('partials.forms.edit.user-select', ['translated_name' => trans('general.select_user'), 'fieldname' => 'assigned_to', 'required'=> 'true']) diff --git a/resources/views/consumables/view.blade.php b/resources/views/consumables/view.blade.php index 80987335ff..5a25659fbe 100644 --- a/resources/views/consumables/view.blade.php +++ b/resources/views/consumables/view.blade.php @@ -45,6 +45,17 @@ @endcan +
  • + + + + +
  • + @can('update', $consumable)
  • @@ -95,7 +106,56 @@ - @can('consumables.files', $consumable) +
    + +
    +
    + + + + + + + + + + + + + + + + + + + +
    {{ trans('general.date') }}{{ trans('general.admin') }}{{ trans('general.action') }}{{ trans('general.file_name') }}{{ trans('general.item') }}{{ trans('general.target') }}{{ trans('general.notes') }}{{ trans('general.signature') }}{{ trans('general.download') }}{{ trans('admin/hardware/table.changed')}}{{ trans('admin/settings/general.login_ip') }}{{ trans('admin/settings/general.login_user_agent') }}{{ trans('general.action_source') }}
    +
    +
    +
    + + + @can('consumables.files', $consumable)
    @@ -176,6 +236,7 @@ {{ trans('general.delete') }} + @endforeach @@ -254,6 +315,19 @@
    @endif + @if ($consumable->notes) + +
    + + {{ trans('general.notes') }}: + +
    +
    + {!! nl2br(Helper::parseEscapedMarkedownInline($consumable->notes)) !!} +
    + + @endif + @can('checkout', \App\Models\Consumable::class)
    @@ -268,22 +342,24 @@ @endif
    + @can('update', \App\Models\Consumable::class) + + @endcan + + @can('delete', $consumable) +
    + @if ($consumable->deleted_at=='') + + {{ trans('general.delete') }} + @endif +
    + @endcan @endcan - @if ($consumable->notes) - -
    - - {{ trans('general.notes') }}: - -
    -
    - {!! nl2br(Helper::parseEscapedMarkedownInline($consumable->notes)) !!} -
    -
    - @endif - @@ -297,5 +373,16 @@ @stop @section('moar_scripts') + + @include ('partials.bootstrap-table', ['exportFile' => 'consumable' . $consumable->name . '-export', 'search' => false]) @stop diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index 74e9d5be6f..63c5bca440 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -976,7 +976,7 @@ dir="{{ in_array(app()->getLocale(),['ar-SA','fa-IR', 'he-IL']) ? 'rtl' : 'ltr' // Reference: https://jqueryvalidation.org/validate/ $('#create-form').validate({ ignore: 'input[type=hidden]', - errorClass: 'help-block form-error', + errorClass: 'alert-msg', errorElement: 'span', errorPlacement: function(error, element) { $(element).hasClass('select2') || $(element).hasClass('js-data-ajax') diff --git a/resources/views/partials/forms/edit/category-select.blade.php b/resources/views/partials/forms/edit/category-select.blade.php index f555c6240b..66800deedf 100644 --- a/resources/views/partials/forms/edit/category-select.blade.php +++ b/resources/views/partials/forms/edit/category-select.blade.php @@ -25,4 +25,6 @@ {!! $errors->first($fieldname, '
    ') !!} + + {!! $errors->first('category_type', '
    ') !!} diff --git a/resources/views/partials/forms/edit/minimum_quantity.blade.php b/resources/views/partials/forms/edit/minimum_quantity.blade.php index 1566ab2e9c..798c6fe72d 100644 --- a/resources/views/partials/forms/edit/minimum_quantity.blade.php +++ b/resources/views/partials/forms/edit/minimum_quantity.blade.php @@ -3,13 +3,13 @@
    - +
    {!! $errors->first('min_amt', '') !!} diff --git a/resources/views/partials/forms/edit/quantity.blade.php b/resources/views/partials/forms/edit/quantity.blade.php index f8a421adcd..b41d13f650 100644 --- a/resources/views/partials/forms/edit/quantity.blade.php +++ b/resources/views/partials/forms/edit/quantity.blade.php @@ -4,8 +4,10 @@
    - +
    +
    {!! $errors->first('qty', '') !!} +
    diff --git a/tests/Feature/Categories/Api/IndexCategoriesTest.php b/tests/Feature/Categories/Api/IndexCategoriesTest.php index fc48fdc547..d27bfbb068 100644 --- a/tests/Feature/Categories/Api/IndexCategoriesTest.php +++ b/tests/Feature/Categories/Api/IndexCategoriesTest.php @@ -32,7 +32,6 @@ class IndexCategoriesTest extends TestCase 'limit' => '20', ])) ->assertOk() - ->assertOk() ->assertJsonStructure([ 'total', 'rows', diff --git a/tests/Feature/Consumables/Api/ConsumableIndexTest.php b/tests/Feature/Consumables/Api/ConsumableIndexTest.php index b16dfdfa53..f1d3ad7f0b 100644 --- a/tests/Feature/Consumables/Api/ConsumableIndexTest.php +++ b/tests/Feature/Consumables/Api/ConsumableIndexTest.php @@ -54,4 +54,29 @@ class ConsumableIndexTest extends TestCase ->assertResponseDoesNotContainInRows($consumableA) ->assertResponseContainsInRows($consumableB); } + + public function testConsumableIndexReturnsExpectedSearchResults() + { + Consumable::factory()->count(10)->create(); + Consumable::factory()->count(1)->create(['name' => 'My Test Consumable']); + + $this->actingAsForApi(User::factory()->superuser()->create()) + ->getJson( + route('api.consumables.index', [ + 'search' => 'My Test Consumable', + 'sort' => 'name', + 'order' => 'asc', + 'offset' => '0', + 'limit' => '20', + ])) + ->assertOk() + ->assertJsonStructure([ + 'total', + 'rows', + ]) + ->assertJson([ + 'total' => 1, + ]); + + } } diff --git a/tests/Feature/Consumables/Api/ConsumableUpdateTest.php b/tests/Feature/Consumables/Api/ConsumableUpdateTest.php new file mode 100644 index 0000000000..1c1e05d4d4 --- /dev/null +++ b/tests/Feature/Consumables/Api/ConsumableUpdateTest.php @@ -0,0 +1,52 @@ +create(); + + $this->actingAsForApi(User::factory()->superuser()->create()) + ->patchJson(route('api.consumables.update', $consumable), [ + 'name' => 'Test Consumable', + ]) + ->assertOk() + ->assertStatusMessageIs('success') + ->assertStatus(200) + ->json(); + + $consumable->refresh(); + $this->assertEquals('Test Consumable', $consumable->name, 'Name was not updated'); + + } + + public function testCannotUpdateConsumableViaPatchWithInvalidCategoryType() + { + $category = Category::factory()->create(['category_type' => 'asset']); + $consumable = Consumable::factory()->create(); + + $this->actingAsForApi(User::factory()->superuser()->create()) + ->patchJson(route('api.consumables.update', $consumable), [ + 'name' => 'Test Consumable', + 'category_id' => $category->id, + ]) + ->assertOk() + ->assertStatusMessageIs('error') + ->assertStatus(200) + ->json(); + + $category->refresh(); + $this->assertNotEquals('Test Consumable', $consumable->name, 'Name was not updated'); + $this->assertNotEquals('consumable', $consumable->category_id, 'Category was not updated'); + + } + +} diff --git a/tests/Feature/Consumables/Api/ConsumableViewTest.php b/tests/Feature/Consumables/Api/ConsumableViewTest.php new file mode 100644 index 0000000000..c6410216e1 --- /dev/null +++ b/tests/Feature/Consumables/Api/ConsumableViewTest.php @@ -0,0 +1,51 @@ +count(2)->create(); + + $consumableA = Consumable::factory()->for($companyA)->create(); + $consumableB = Consumable::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewConsumables()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewConsumables()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + $this->actingAsForApi($superUser) + ->getJson(route('api.consumables.show', $consumableA)) + ->assertOk(); + + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.consumables.show', $consumableA)) + ->assertOk(); + + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.consumables.show', $consumableB)) + ->assertOk(); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAsForApi($superUser) + ->getJson(route('api.consumables.show', $consumableA)) + ->assertOk(); + + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.consumables.index')) + ->assertOk(); + + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.consumables.index')) + ->assertOk(); + } +} diff --git a/tests/Feature/Consumables/Ui/ConsumableViewTest.php b/tests/Feature/Consumables/Ui/ConsumableViewTest.php new file mode 100644 index 0000000000..9633896c2d --- /dev/null +++ b/tests/Feature/Consumables/Ui/ConsumableViewTest.php @@ -0,0 +1,26 @@ +create(); + $this->actingAs(User::factory()->create()) + ->get(route('consumables.show', $consumable)) + ->assertForbidden(); + } + + public function testUserCanListConsumables() + { + $consumable = Consumable::factory()->create(); + $this->actingAs(User::factory()->superuser()->create()) + ->get(route('consumables.show', $consumable)) + ->assertOk(); + } +}