diff --git a/app/Http/Controllers/Consumables/BulkConsumablesController.php b/app/Http/Controllers/Consumables/BulkConsumablesController.php new file mode 100644 index 0000000000000000000000000000000000000000..1cb29846bf5815aa0504be1a548997490e231d95 --- /dev/null +++ b/app/Http/Controllers/Consumables/BulkConsumablesController.php @@ -0,0 +1,195 @@ +<?php + +namespace App\Http\Controllers\Consumables; + +use App\Helpers\Helper; +use App\Http\Controllers\CheckInOutRequest; +use App\Http\Controllers\Controller; +use App\Models\Consumable; +use App\Models\Setting; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; + +class BulkConsumablesController extends Controller +{ + use CheckInOutRequest; + + /** + * Display the bulk edit page. + * + * @author [A. Gianotto] [<snipe@snipe.net>] + * @return View + * @internal param int $assetId + * @since [v2.0] + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function edit(Request $request) + { + $this->authorize('update', Consumable::class); + + if (!$request->filled('ids')) { + return redirect()->back()->with('error', 'No assets selected'); + } + + $consumable_ids = array_keys($request->input('ids')); + + if ($request->filled('bulk_actions')) { + switch($request->input('bulk_actions')) { + case 'labels': + return view('consumables/labels') + ->with('consumables', Consumable::find($consumable_ids)) + ->with('settings', Setting::getSettings()) + ->with('bulkedit', true) + ->with('count', 0); + case 'delete': + $consumables = Consumable::find($consumable_ids); + $consumables->each(function ($consumable) { + $this->authorize('delete', $consumable); + }); + return view('consumables/bulk-delete')->with('consumables', $consumables); + case 'edit': + return view('consumables/bulk') + ->with('consumables', request('ids')); + } + } + return redirect()->back()->with('error', 'No action selected'); + } + + /** + * Save bulk edits + * + * @author [A. Gianotto] [<snipe@snipe.net>] + * @return Redirect + * @internal param array $assets + * @since [v2.0] + */ + public function update(Request $request) + { + $this->authorize('update', Consumable::class); + \Log::debug($request->input('ids')); + + if(!$request->filled('ids') || count($request->input('ids')) <= 0) { + return redirect()->route("consumables.index")->with('warning', trans('No consumables selected, so nothing was updated.')); //TODO: trans + } + + $consumables = array_keys($request->input('ids')); + + if (($request->filled('purchase_date')) + || ($request->filled('purchase_cost')) + || ($request->filled('category_id')) + || ($request->filled('order_number')) + || ($request->filled('location_id')) + || ($request->filled('qty')) + || ($request->filled('company_id')) + || ($request->filled('manufacturer_id')) + || ($request->filled('min_amt')) + || ($request->filled('model_number')) + ) { + foreach ($consumables as $consumableId) { + $this->update_array = []; + + $this->conditionallyAddItem('purchase_date') + ->conditionallyAddItem('purchase_cost') + ->conditionallyAddItem('order_number') + ->conditionallyAddItem('requestable') + ->conditionallyAddItem('status_id') + ->conditionallyAddItem('supplier_id') + ->conditionallyAddItem('category_id') + ->conditionallyAddItem('manufacturer_id') + ->conditionallyAddItem('qty') + ->conditionallyAddItem('min_amt') + ->conditionallyAddItem('warranty_months'); + + if ($request->filled('purchase_cost')) { + $this->update_array['purchase_cost'] = Helper::ParseFloat($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; + } + } + + if ($request->filled('qty')) { + $this->update_array['qty'] = $request->input('qty'); + } + + if ($request->filled('min_amt')) { + $this->update_array['min_amt'] = $request->input('min_amt'); + } + + if ($request->filled('category_id')) { + $this->update_array['category_id'] = $request->input('category_id'); + } + + if ($request->filled('location_id')) { + $this->update_array['location_id'] = $request->input('location_id'); + } + + if ($request->filled('manufacturer_id')) { + $this->update_array['manufacturer_id'] = $request->input('manufacturer_id'); + } + + \Log::debug(implode(", ", $this->update_array)); + \Log::debug(implode(", ", array_keys($this->update_array))); + DB::table('consumables') + ->where('id', $consumableId) + ->update($this->update_array); + } // endforeach + return redirect()->route("consumables.index")->with('success', trans('admin/consumables/message.update.success')); + // no values given, nothing to update + } + return redirect()->route("consumables.index")->with('warning', trans('admin/consumables/message.update.nothing_updated')); + + } + + /** + * Array to store update data per item + * @var Array + */ + private $update_array; + + /** + * Adds parameter to update array for an item if it exists in request + * @param String $field field name + * @return BulkAssetsController Model for Chaining + */ + protected function conditionallyAddItem($field) + { + if(request()->filled($field)) { + $this->update_array[$field] = request()->input($field); + } + return $this; + } + + /** + * Save bulk deleted. + * + * @author [A. Gianotto] [<snipe@snipe.net>] + * @param Request $request + * @return View + * @throws \Illuminate\Auth\Access\AuthorizationException + * @internal param array $assets + * @since [v2.0] + */ + public function destroy(Request $request) + { + $this->authorize('delete', Consumable::class); + + if ($request->filled('ids')) { + $consumables = Consumable::find($request->get('ids')); + foreach ($consumables as $consumable) { + $update_array['deleted_at'] = date('Y-m-d H:i:s'); + + DB::table('consumables') + ->where('id', $consumable->id) + ->update($update_array); + } // endforeach + return redirect()->to("consumables")->with('success', trans('admin/consumables/message.delete.success')); + // no values given, nothing to update + } + return redirect()->to("consumables")->with('info', trans('admin/consumables/message.delete.nothing_updated')); + } +} diff --git a/resources/lang/en/admin/consumables/form.php b/resources/lang/en/admin/consumables/form.php new file mode 100644 index 0000000000000000000000000000000000000000..98f265153268197a7ce1141b1bc58ee34ad9862f --- /dev/null +++ b/resources/lang/en/admin/consumables/form.php @@ -0,0 +1,24 @@ +<?php + +return array( + 'bulk_delete' => 'Confirm Bulk Delete Consumables', + 'bulk_delete_help' => 'Review the consumables for bulk deletion below. Once deleted, these consumables can be restored.', + 'bulk_delete_warn' => 'You are about to delete :consumable_count consumables.', + 'bulk_update' => 'Bulk Update Consumables', + 'bulk_update_help' => 'This form allows you to update multiple consumables at once. Only fill in the fields you need to change. Any fields left blank will remain unchanged. ', + 'bulk_update_warn' => 'You are about to edit the properties of :consumable_count consumables.', + 'cost' => 'Purchase Cost', + 'create' => 'Create Asset', + 'date' => 'Purchase Date', + 'manufacturer' => 'Manufacturer', + 'model' => 'Model', + 'months' => 'months', + 'name' => 'Asset Name', + 'notes' => 'Notes', + 'order' => 'Order Number', + 'qr' => 'QR Code', + 'category' => 'Consumable Category', + 'update' => 'Consumable Update', + 'years' => 'years', +) +; diff --git a/resources/views/consumables/bulk-delete.blade.php b/resources/views/consumables/bulk-delete.blade.php new file mode 100644 index 0000000000000000000000000000000000000000..940659942642d91ac7cd716fe62651b12cc1bc58 --- /dev/null +++ b/resources/views/consumables/bulk-delete.blade.php @@ -0,0 +1,62 @@ +@extends('layouts/default') + +{{-- Page title --}} +@section('title') +{{ trans('admin/consumables/form.bulk_delete') }} +@parent +@stop + +@section('header_right') +<a href="{{ URL::previous() }}" class="btn btn-primary pull-right"> + {{ trans('general.back') }}</a> +@stop + +{{-- Page content --}} +@section('content') +<div class="row"> + <!-- left column --> + <div class="col-md-12"> + <p>{{ trans('admin/consumables/form.bulk_delete_help') }}</p> + <form class="form-horizontal" method="post" action="{{ route('consumables/bulkdelete') }}" autocomplete="off" role="form"> + {{csrf_field()}} + <div class="box box-default"> + <div class="box-header with-border"> + <h2 class="box-title" style="color: red">{{ trans('admin/consumables/form.bulk_delete_warn', ['consumable_count' => count($consumables)]) }}</h2> + </div> + + <div class="box-body"> + <table class="table table-striped table-condensed"> + <thead> + <tr> + <td></td> + <td>ID</td> + <td>Name</td> + <td>Location</td> + </tr> + </thead> + <tbody> + @foreach ($consumables as $consumable) + <tr> + <td><input type="checkbox" name="ids[]" value="{{ $consumable->id }}" checked="checked"></td> + <td>{{ $consumable->id }}</td> + <td>{{ $consumable->present()->name() }}</td> + <td> + @if ($consumable->location) + {{ $consumable->location->name }} + @endif + </td> + </tr> + @endforeach + </tbody> + </table> + </div><!-- /.box-body --> + + <div class="box-footer text-right"> + <a class="btn btn-link" href="{{ URL::previous() }}" method="post" enctype="multipart/form-data">{{ trans('button.cancel') }}</a> + <button type="submit" class="btn btn-success" id="submit-button"><i class="fa fa-check icon-white" aria-hidden="true"></i> {{ trans('general.delete') }}</button> + </div><!-- /.box-footer --> + </div><!-- /.box --> + </form> + </div> <!-- .col-md-12--> +</div><!--.row--> +@stop diff --git a/resources/views/consumables/bulk.blade.php b/resources/views/consumables/bulk.blade.php new file mode 100644 index 0000000000000000000000000000000000000000..2761883f4a9be0ba5927fc481eeeff1d44b181b7 --- /dev/null +++ b/resources/views/consumables/bulk.blade.php @@ -0,0 +1,199 @@ +@extends('layouts/default') + +{{-- Page title --}} +@section('title') +{{ trans('admin/consumables/form.update') }} +@parent +@stop + + +@section('header_right') +<a href="{{ URL::previous() }}" class="btn btn-sm btn-primary pull-right"> + {{ trans('general.back') }}</a> +@stop + +{{-- Page content --}} +@section('content') +<div class="row"> + <div class="col-md-8 col-md-offset-2"> + + <p>{{ trans('admin/consumables/form.bulk_update_help') }}</p> + + <div class="callout callout-warning"> + <i class="fa fa-warning"></i> {{ trans('admin/consumables/form.bulk_update_warn', ['consumable_count' => count($consumables)]) }} + </div> + + <form class="form-horizontal" method="post" action="{{ route('consumables/bulksave') }}" autocomplete="off" role="form"> + {{ csrf_field() }} + + <div class="box box-default"> + <div class="box-body"> + + <!-- Company --> + @include ('partials.forms.edit.company-select', ['translated_name' => trans('general.company'), 'fieldname' => 'company_id']) + + <!-- Category --> + <div id="{{ 'category_id' }}" class="form-group category_id"> + + {{ Form::label('category_id', trans('general.category'), array('class' => 'col-md-3 control-label')) }} + + <div class="col-md-7"> + <select class="js-data-ajax" data-endpoint="categories/{{ (isset($category_type)) ? $category_type : 'consumable' }}" data-placeholder="{{ trans('general.select_category') }}" name="category_id" style="width: 100%" id="category_select_id" aria-label="category_id"> + <option value="" role="option">{{ trans('general.select_category') }}</option> + + </select> + </div> + <div class="col-md-1 col-sm-1 text-left"> + @can('create', \App\Models\Category::class) + @if ((!isset($hide_new)) || ($hide_new!='true')) + <a href='{{ route('modal.show',['type' => 'category', 'category_type' => isset($category_type) ? $category_type : 'consumable' ]) }}' data-toggle="modal" data-target="#createModal" data-select='category_select_id' class="btn btn-sm btn-primary">New</a> + @endif + @endcan + </div> + + + {!! $errors->first('category_id', '<div class="col-md-8 col-md-offset-3"><span class="alert-msg" aria-hidden="true"><i class="fa fa-times" aria-hidden="true"></i> :message</span></div>') !!} + </div> + + <!-- Manufacturer --> + <div id="manufacturer_id" class="form-group manufacturer_id"> + {{ Form::label('manufacturer_id', trans('general.manufacturer'), array('class' => 'col-md-3 control-label')) }} + + <div class="col-md-7"> + <select class="js-data-ajax" data-endpoint="manufacturers" data-placeholder="{{ trans('general.select_manufacturer') }}" name="manufacturer_id" style="width: 100%" id="manufacturer_select_id" aria-label="manufacturer_id"> + <option value="" role="option">{{ trans('general.select_manufacturer') }}</option> + </select> + </div> + + <div class="col-md-1 col-sm-1 text-left"> + @can('create', \App\Models\Manufacturer::class) + @if ((!isset($hide_new)) || ($hide_new!='true')) + <a href='{{ route('modal.show', 'manufacturer') }}' data-toggle="modal" data-target="#createModal" data-select='manufacturer_select_id' class="btn btn-sm btn-primary">New</a> + @endif + @endcan + </div> + + + {!! $errors->first('manufacturer_id', '<div class="col-md-8 col-md-offset-3"><span class="alert-msg" aria-hidden="true"><i class="fa fa-times" aria-hidden="true"></i> :message</span></div>') !!} + </div> + + <!-- Location --> + <div id="location_id" class="form-group location_id"{!! (isset($style)) ? ' style="'.e($style).'"' : '' !!}> + + {{ Form::label('location_id', trans('general.location'), array('class' => 'col-md-3 control-label')) }} + <div class="col-md-6"> + <select class="js-data-ajax" data-endpoint="locations" data-placeholder="{{ trans('general.select_location') }}" name="location_id" style="width: 100%" id="location_id_location_select" aria-label="location_id"> + <option value="" role="option">{{ trans('general.select_location') }}</option> + </select> + </div> + + <div class="col-md-1 col-sm-1 text-left"> + @can('create', \App\Models\Location::class) + @if ((!isset($hide_new)) || ($hide_new!='true')) + <a href='{{ route('modal.show', 'location') }}' data-toggle="modal" data-target="#createModal" data-select='location_id_location_select' class="btn btn-sm btn-primary">New</a> + @endif + @endcan + </div> + + {!! $errors->first('location_id', '<div class="col-md-8 col-md-offset-3"><span class="alert-msg" aria-hidden="true"><i class="fa fa-times" aria-hidden="true"></i> :message</span></div>') !!} + + @if (isset($help_text)) + <div class="col-md-7 col-sm-11 col-md-offset-3"> + <p class="help-block">{{ $help_text }}</p> + </div> + @endif + </div> + + <!-- Model Number --> + <div class="form-group {{ $errors->has('model_number') ? ' has-error' : '' }}"> + <label for="model_number" class="col-md-3 control-label">{{ trans('general.model_no') }}</label> + <div class="col-md-7"> + <input class="form-control" type="text" name="model_number" aria-label="model_number" id="model_number" value="" /> + {!! $errors->first('model_number', '<span class="alert-msg" aria-hidden="true"><i class="fa fa-times" aria-hidden="true"></i> :message</span>') !!} + </div> + </div> + + <!-- Order Number --> + <div class="form-group {{ $errors->has('order_number') ? ' has-error' : '' }}"> + <label for="order_number" class="col-md-3 control-label">{{ trans('general.order_number') }}</label> + <div class="col-md-7 col-sm-12"> + <input class="form-control" type="text" name="order_number" aria-label="order_number" id="order_number" value="" /> + {!! $errors->first('order_number', '<span class="alert-msg" aria-hidden="true"><i class="fa fa-times" aria-hidden="true"></i> :message</span>') !!} + </div> + </div> + + <!-- Purchase Date --> + <div class="form-group {{ $errors->has('purchase_date') ? ' has-error' : '' }}"> + <label for="purchase_date" class="col-md-3 control-label">{{ trans('general.purchase_date') }}</label> + <div class="input-group col-md-3"> + <div class="input-group date" data-provide="datepicker" data-date-format="yyyy-mm-dd" data-autoclose="true"> + <input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="purchase_date" id="purchase_date" value=""> + <span class="input-group-addon"><i class="fa fa-calendar" aria-hidden="true"></i></span> + </div> + {!! $errors->first('purchase_date', '<span class="alert-msg" aria-hidden="true"><i class="fa fa-times" aria-hidden="true"></i> :message</span>') !!} + </div> + </div> + + <!-- Purchase Cost --> + <div class="form-group {{ $errors->has('purchase_cost') ? ' has-error' : '' }}"> + <label for="purchase_cost" class="col-md-3 control-label">{{ trans('general.purchase_cost') }}</label> + <div class="col-md-9"> + <div class="input-group col-md-4" style="padding-left: 0px;"> + <input class="form-control" type="text" name="purchase_cost" aria-label="purchase_cost" id="purchase_cost" value="" /> + <span class="input-group-addon"> + @if (isset($currency_type)) + {{ $currency_type }} + @else + {{ $snipeSettings->default_currency }} + @endif + </span> + </div> + <div class="col-md-9" style="padding-left: 0px;"> + {!! $errors->first('purchase_cost', '<span class="alert-msg" aria-hidden="true"><i class="fa fa-times" aria-hidden="true"></i> :message</span>') !!} + </div> + </div> + </div> + + <!-- QTY --> + <div class="form-group {{ $errors->has('qty') ? ' has-error' : '' }}"> + <label for="qty" class="col-md-3 control-label">{{ trans('general.quantity') }}</label> + <div class="col-md-7"> + <div class="col-md-2" style="padding-left:0px"> + <input class="form-control" type="text" name="qty" aria-label="qty" id="qty" value=""> + </div> + {!! $errors->first('qty', '<span class="alert-msg" aria-hidden="true"><i class="fa fa-times" aria-hidden="true"></i> :message</span>') !!} + </div> + </div> + + <!-- Min QTY --> + <div class="form-group{{ $errors->has('min_amt') ? ' has-error' : '' }}"> + <label for="min_amt" class="col-md-3 control-label">{{ trans('general.min_amt') }}</label> + <div class="col-md-9"> + <div class="col-md-2" style="padding-left:0px"> + <input class="form-control col-md-3" type="text" name="min_amt" id="min_amt" aria-label="min_amt" value="" /> + </div> + <div class="col-md-7" style="margin-left: -15px;"> + <a href="#" data-toggle="tooltip" title="{{ trans('general.min_amt_help') }}"><i class="fa fa-info-circle" aria-hidden="true"></i> + <span class="sr-only">{{ trans('general.min_amt_help') }}</span> + </a> + + </div> + <div class="col-md-12"> + {!! $errors->first('min_amt', '<span class="alert-msg" aria-hidden="true"><i class="fa fa-times" aria-hidden="true"></i> :message</span>') !!} + </div> + </div> + </div> + + @foreach ($consumables as $key => $value) + <input type="hidden" name="ids[{{ $key }}]" value="1"> + @endforeach + </div> <!--/.box-body--> + + <div class="text-right box-footer"> + <button type="submit" class="btn btn-success"><i class="fa fa-check icon-white" aria-hidden="true"></i> {{ trans('general.save') }}</button> + </div> + </div> <!--/.box.box-default--> + </form> + </div> <!--/.col-md-8--> +</div> +@stop