<?php

namespace App\Models;

use App\Models\Traits\HasCategoryTrait;
use App\Models\Traits\HasEventsTrait;
use App\Models\Traits\HasNotesTrait;
use App\Models\Traits\HasScopeArchivedTrait;
use App\Models\Traits\HasScopeIdTrait;
use App\Models\Traits\HasUserTrait;
use App\Viewers\Inventory\InventoryViewer;
use Illuminate\Database\Eloquent\SoftDeletes;
use Stevebauman\Inventory\Traits\InventoryTrait;
use Stevebauman\Inventory\Traits\InventoryVariantTrait;

class Inventory extends Model
{
    use SoftDeletes;

    use InventoryTrait;
    use InventoryVariantTrait;

    use HasScopeArchivedTrait;
    use HasScopeIdTrait;
    use HasCategoryTrait;
    use HasEventsTrait;
    use HasUserTrait;
    use HasNotesTrait;

    /**
     * The database table to store inventory records.
     *
     * @var string
     */
    protected $table = 'inventories';

    /**
     * The fillable eloquent attribute array for allowing mass assignments.
     *
     * @var array
     */
    protected $fillable = [
        'user_id',
        'metric_id',
        'category_id',
        'name',
        'description',
        'is_assembly',
    ];

    /**
     * The columns to keep revisions of.
     *
     * @var array
     */
    protected $revisionColumns = [
        'metric_id',
        'category_id',
        'name',
        'description',
    ];

    /**
     * The revision column means attributes.
     *
     * @var array
     */
    protected $revisionColumnsMean = [
        'metric_id'   => 'revised_metric',
        'category_id' => 'revised_category',
    ];

    /**
     * Revisionable field names.
     *
     * @var array
     */
    protected $revisionColumnsFormatted = [
        'category_id' => 'Category',
        'metric_id'   => 'Metric',
        'name'        => 'Name',
        'description' => 'Description',
    ];

    /**
     * The inventory viewer class.
     *
     * @var string
     */
    protected $viewer = InventoryViewer::class;

    /**
     * The hasOne metric relationship.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function metric()
    {
        return $this->hasOne(Metric::class, 'id', 'metric_id');
    }

    /**
     * The hasOne SKU relationship.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function sku()
    {
        return $this->hasOne(InventorySku::class, 'inventory_id', 'id');
    }

    /**
     * The hasMany stocks relationship.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function stocks()
    {
        return $this->hasMany(InventoryStock::class, 'inventory_id');
    }

    /**
     * The hasMany assemblies relationship.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function assemblies()
    {
        return $this->hasMany(InventoryAssembly::class, 'inventory_id');
    }

    /**
     * The hasMany suppliers relationship.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function suppliers()
    {
        return $this->belongsToMany(Supplier::class, 'inventory_suppliers', 'inventory_id')->withTimestamps();
    }

    /**
     * Filters query by the inputted inventory item name.
     *
     * @param $query
     * @param string $name
     *
     * @return mixed
     */
    public function scopeName($query, $name = null)
    {
        if ($name) {
            return $query->where('name', 'LIKE', '%'.$name.'%');
        }

        return $query;
    }

    /**
     * Filters query by the inputted inventory item description.
     *
     * @param $query
     * @param string $description
     *
     * @return mixed
     */
    public function scopeDescription($query, $description = null)
    {
        if ($description) {
            return $query->where('description', 'LIKE', '%'.$description.'%');
        }

        return $query;
    }

    /**
     * Filters query by the inputted inventory item stock quantity.
     *
     * @param $query
     * @param string $operator
     * @param string $stock
     *
     * @return mixed
     */
    public function scopeStock($query, $operator = null, $stock = null)
    {
        if ($operator && $stock) {
            return $query->whereHas('stocks', function ($query) use ($operator, $stock) {
                if ($output = $this->getOperator($operator)) {
                    return $query->where('quantity', $output[0], $stock);
                } else {
                    return $query;
                }
            });
        }

        return $query;
    }

    /**
     * Filters query by the inputted inventory sku.
     *
     * @param $query
     * @param string $sku
     *
     * @return mixed
     */
    public function scopeSku($query, $sku = null)
    {
        if ($sku) {
            return $query->whereHas('sku', function ($query) use ($sku) {
                return $query->where('code', 'LIKE', '%'.$sku.'%');
            });
        }

        return $query;
    }

    /**
     * Filters inventory results by showing
     * only parent inventory items.
     *
     * @param $query
     *
     * @return mixed
     */
    public function scopeNoVariants($query)
    {
        return $query->whereNull('parent_id');
    }

    /**
     * Mutator for showing the total current stock of the inventory item.
     *
     * @return int|string
     */
    public function getCurrentStockAttribute()
    {
        $stock = $this->getTotalStock();

        if ($this->hasMetric()) {
            return sprintf('%s %s', $stock, $this->getMetricSymbol());
        }

        return $stock;
    }

    /**
     * Mutator for showing the inventories metric symbol.
     *
     * @return null|string
     */
    public function getMetricSymbolAttribute()
    {
        if ($this->hasMetric()) {
            return $this->getMetricSymbol();
        }

        return;
    }

    /**
     * Retrieves the revised metric attribute.
     *
     * @param int|string $id
     *
     * @return null|string
     */
    public function getRevisedMetricAttribute($id)
    {
        if ($id) {
            $metric = $this->metric()->find($id);

            if ($metric) {
                return $metric->name;
            }
        }

        return;
    }
}


<?php

namespace App\Models;

use App\Models\Traits\HasScopeIdTrait;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Support\Facades\Schema;
use Stevebauman\EloquentTable\TableTrait;
use Stevebauman\Revision\Traits\HasRevisionsTrait;
use Stevebauman\Viewer\Traits\ViewableTrait;

class Model extends Eloquent
{
    /*
     * Provides easy table generation.
     */
    use TableTrait;

    /*
     * Provides scope for viewing a specific record ID.
     */
    use HasScopeIdTrait;

    /*
     * Provides reusable views when an object is returned.
     */
    use ViewableTrait;

    /*
     * Provides model revisions.
     */
    use HasRevisionsTrait;

    /**
     * The morphMany revisions relationship.
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function revisions()
    {
        return $this->morphMany(Revision::class, 'revisionable');
    }

    /**
     * Returns the revision user ID.
     *
     * @return int
     */
    public function revisionUserId()
    {
        return auth()->id();
    }

    /**
     * Formats the created_at timestamp.
     *
     * @param string $createdAt
     *
     * @return string
     */
    public function getCreatedAtAttribute($createdAt)
    {
        return Carbon::parse($createdAt)->format('Y-m-d h:i A');
    }

    /**
     * Accessor for retrieving a limited description for display on tables.
     *
     * @return string
     */
    public function getLimitedDescriptionAttribute()
    {
        if (array_key_exists('description', $this->attributes)) {

            /*
             * Strip tags due to HTML formatting that may be inside the description
             * that could ruin the display of the table
             */
            return str_limit(strip_tags($this->attributes['description']), 30);
        }

        return;
    }

    /**
     * Retrieves a valid operator from the specified string.
     *
     * @param string $string
     *
     * @return bool|array
     */
    protected function getOperator($string)
    {
        $allowed_operators = ['>', '<', '=', '>=', '<='];

        $output = preg_split("/[\[\]]/", $string);

        if (is_array($output)) {
            if (array_key_exists('1', $output) && array_key_exists('2', $output)) {
                if (in_array($output[1], $allowed_operators)) {
                    return [$output[1], $output[2]];
                }
            } else {
                return $output;
            }
        }

        return false;
    }

    /**
     * Scopes a query to show only soft deleted records.
     *
     * @param object $query
     * @param bool   $archived
     *
     * @return object
     */
    public function scopeArchived($query, $archived = false)
    {
        if ($archived) {
            return $query->onlyTrashed();
        }

        return $query;
    }

    /**
     * Allows all columns on the current database table to be sorted through
     * query scope.
     *
     * @param object $query
     * @param string $field
     * @param string $sort
     *
     * @return object
     */
    public function scopeSort($query, $field = null, $sort = null)
    {
        /*
         * Make sure both the field and sort variables are present
         */
        if ($field && $sort) {
            /*
             * Retrieve all column names for the current model table
             */
            $columns = Schema::getColumnListing($this->getTable());

            /*
             * Make sure the field inputted is available on the current table
             */
            if (in_array($field, $columns)) {

                /*
                 * Make sure the sort input is equal to asc or desc
                 */
                if ($sort === 'asc' || $sort === 'desc') {
                    /*
                     * Return the query sorted
                     */
                    return $query->orderBy($field, $sort);
                }
            }
        }

        /*
         * Default to latest scope
         */
        return $query->latest();
    }
}


<?php

namespace App\Http\Controllers\WorkOrder;

use App\Http\Controllers\Controller;
use App\Http\Requests\WorkOrder\WorkOrderRequest;
use App\Processors\WorkOrder\WorkOrderProcessor;

class WorkOrderController extends Controller
{
    /**
     * @var WorkOrderProcessor
     */
    protected $processor;

    /**
     * Constructor.
     *
     * @param WorkOrderProcessor $processor
     */
    public function __construct(WorkOrderProcessor $processor)
    {
        $this->processor = $processor;
    }

    /**
     * Displays work orders paginated.
     *
     * @return \Illuminate\View\View
     */
    public function index()
    {
        return $this->processor->index();
    }

    /**
     * Displays the form to create a work order.
     *
     * @return \Illuminate\View\View
     */
    public function create()
    {
        return $this->processor->create();
    }

    /**
     * Creates a new work order.
     *
     * @param WorkOrderRequest $request
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store(WorkOrderRequest $request)
    {
        if ($this->processor->store($request)) {
            flash()->success('Success!', 'Successfully created work order.');

            return redirect()->route('maintenance.work-orders.index');
        } else {
            flash()->error('Error!', 'There was an issue creating this work order. Please try again.');

            return redirect()->route('maintenance.work-orders.create');
        }
    }

    /**
     * Displays the specified work order.
     *
     * @param int|string $id
     *
     * @return \Illuminate\View\View
     */
    public function show($id)
    {
        return $this->processor->show($id);
    }

    /**
     * Displays the edit form for the specified work order.
     *
     * @param int|string $id
     *
     * @return \Illuminate\View\View
     */
    public function edit($id)
    {
        return $this->processor->edit($id);
    }

    /**
     * Updates the specified work order.
     *
     * @param WorkOrderRequest $request
     * @param int|string       $id
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(WorkOrderRequest $request, $id)
    {
        if ($this->processor->update($request, $id)) {
            flash()->success('Success!', 'Successfully edited work order.');

            return redirect()->route('maintenance.work-orders.show', [$id]);
        } else {
            flash()->error('Error!', 'There was an issue updating this work order. Please try again.');

            return redirect()->route('maintenance.work-orders.edit', [$id]);
        }
    }

    /**
     * Deletes a work order.
     *
     * @param int|string $id
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function destroy($id)
    {
        if ($this->processor->destroy($id)) {
            flash()->success('Success!', 'Successfully deleted work order.');

            return redirect()->route('maintenance.work-orders.index');
        } else {
            flash()->error('Error!', 'There was an issue deleting this work order. Please try again');

            return redirect()->route('maintenance.work-orders.index');
        }
    }
}


<?php

namespace App\Models;

use App\Models\Traits\HasUserTrait;
use App\Viewers\AttachmentViewer;
use Illuminate\Support\Facades\Storage;

class Attachment extends Model
{
    use HasUserTrait;

    /**
     * The attachments table.
     *
     * @var string
     */
    protected $table = 'attachments';

    /**
     * The storage disk.
     *
     * @var string
     */
    protected $disk = 'local';

    /**
     * The attachments viewer.
     *
     * @var string
     */
    protected $viewer = AttachmentViewer::class;

    /**
     * The fillable attachment attributes.
     *
     * @var array
     */
    protected $fillable = [
        'user_id',
        'name',
        'file_name',
        'file_path',
    ];

    /**
     * Returns the disk to store files on.
     *
     * @return string
     */
    public function getDisk()
    {
        return $this->disk;
    }

    /**
     * Returns the attachments relative storage file path.
     *
     * @return string
     */
    public function getStorageFilePath()
    {
        return $this->file_path;
    }

    /**
     * Returns the full path of the uploaded file.
     *
     * @return string
     */
    public function getFullPathAttribute()
    {
        $config = sprintf('filesystems.%s.root', $this->getDisk());

        $default = storage_path('app');

        $basePath = config($config, $default);

        return $basePath.DIRECTORY_SEPARATOR.$this->file_path;
    }

    /**
     * Returns the complete download path for the uploaded file.
     *
     * @return string
     */
    public function getDownloadPathAttribute()
    {
        return $this->getFullPathAttribute();
    }

    /**
     * Returns the last modified date of the uploaded file.
     *
     * @return string
     */
    public function getLastModifiedAttribute()
    {
        return Storage::disk($this->getDisk())->lastModified($this->file_path);
    }

    /**
     * Returns the size in bytes of the uploaded file.
     *
     * @return string
     */
    public function getSizeAttribute()
    {
        return Storage::disk($this->getDisk())->size($this->file_path);
    }

    /**
     * Returns the extension of the uploaded file.
     *
     * @return string
     */
    public function getMimeTypeAttribute()
    {
        return Storage::disk($this->getDisk())->getMimetype($this->file_path);
    }

    /**
     * Returns a large icon representing the uploaded file type.
     *
     * @return string
     */
    public function getIconAttribute()
    {
        $mime = $this->getMimeTypeAttribute();

        return view('partials.models.attachment.icon', compact('mime'))->render();
    }
}


<?php

namespace App\Processors\WorkOrder;

use App\Http\Presenters\WorkOrder\WorkOrderStatusPresenter;
use App\Http\Requests\WorkOrder\StatusRequest;
use App\Jobs\WorkOrder\Status\Store;
use App\Jobs\WorkOrder\Status\Update;
use App\Models\Status;
use App\Processors\Processor;

class WorkOrderStatusProcessor extends Processor
{
    /**
     * @var Status
     */
    protected $status;

    /**
     * @var WorkOrderStatusPresenter
     */
    protected $presenter;

    /**
     * Constructor.
     *
     * @param Status                   $status
     * @param WorkOrderStatusPresenter $presenter
     */
    public function __construct(Status $status, WorkOrderStatusPresenter $presenter)
    {
        $this->status = $status;
        $this->presenter = $presenter;
    }

    /**
     * Displays all statuses.
     *
     * @return \Illuminate\View\View
     */
    public function index()
    {
        $statuses = $this->presenter->table($this->status);

        $navbar = $this->presenter->navbar();

        return view('work-orders.statuses.index', compact('statuses', 'navbar'));
    }

    /**
     * Displays the form for creating a status.
     *
     * @return \Illuminate\View\View
     */
    public function create()
    {
        $form = $this->presenter->form($this->status);

        return view('work-orders.statuses.create', compact('form'));
    }

    /**
     * Creates a new status.
     *
     * @param StatusRequest $request
     *
     * @return bool
     */
    public function store(StatusRequest $request)
    {
        $status = $this->status->newInstance();

        return $this->dispatch(new Store($request, $status));
    }

    /**
     * Displays the form for editing the specified status.
     *
     * @param int|string $id
     *
     * @return \Illuminate\View\View
     */
    public function edit($id)
    {
        $status = $this->status->findOrFail($id);

        $form = $this->presenter->form($status);

        return view('work-orders.statuses.edit', compact('form'));
    }

    /**
     * Updates the specified status.
     *
     * @param StatusRequest $request
     * @param int|string    $id
     *
     * @return bool
     */
    public function update(StatusRequest $request, $id)
    {
        $status = $this->status->findOrFail($id);

        return $this->dispatch(new Update($request, $status));
    }

    /**
     * Deletes the specified status.
     *
     * @param int|string $id
     *
     * @return bool
     */
    public function destroy($id)
    {
        $status = $this->status->findOrFail($id);

        return $status->delete();
    }
}


<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateInventoryTables extends Migration
{
    /**
     * Run the migrations.
     */
    public function up()
    {
        Schema::create('inventories', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
            $table->softDeletes();

            $table->integer('category_id')->unsigned()->nullable();
            $table->integer('user_id')->unsigned()->nullable();
            $table->integer('metric_id')->unsigned();
            $table->string('name');
            $table->text('description')->nullable();

            $table->foreign('category_id')->references('id')->on('categories')
                ->onUpdate('restrict')
                ->onDelete('set null');

            $table->foreign('user_id')->references('id')->on('users')
                ->onUpdate('restrict')
                ->onDelete('set null');

            $table->foreign('metric_id')->references('id')->on('metrics')
                ->onUpdate('restrict')
                ->onDelete('cascade');
        });

        Schema::create('inventory_stocks', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
            $table->softDeletes();

            $table->integer('user_id')->unsigned()->nullable();
            $table->integer('inventory_id')->unsigned();
            $table->integer('location_id')->unsigned();
            $table->decimal('quantity', 8, 2)->default(0);
            $table->string('aisle')->nullable();
            $table->string('row')->nullable();
            $table->string('bin')->nullable();

            /*
             * This allows only one inventory stock
             * to be created on a single location
             */
            $table->unique(['inventory_id', 'location_id']);

            $table->foreign('user_id')->references('id')->on('users')
                ->onUpdate('restrict')
                ->onDelete('set null');

            $table->foreign('inventory_id')->references('id')->on('inventories')
                ->onUpdate('restrict')
                ->onDelete('cascade');

            $table->foreign('location_id')->references('id')->on('locations')
                ->onUpdate('restrict')
                ->onDelete('cascade');
        });

        Schema::create('inventory_stock_movements', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
            $table->softDeletes();

            $table->integer('stock_id')->unsigned();
            $table->integer('user_id')->unsigned()->nullable();
            $table->decimal('before', 8, 2)->default(0);
            $table->decimal('after', 8, 2)->default(0);
            $table->decimal('cost', 8, 2)->default(0)->nullable();
            $table->string('reason')->nullable();

            $table->foreign('stock_id')->references('id')->on('inventory_stocks')
                ->onUpdate('restrict')
                ->onDelete('cascade');

            $table->foreign('user_id')->references('id')->on('users')
                ->onUpdate('restrict')
                ->onDelete('set null');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down()
    {
        Schema::dropIfExists('inventory_stock_movements');
        Schema::dropIfExists('inventory_stocks');
        Schema::dropIfExists('inventories');
    }
}


<?php

namespace App\Processors\Inventory;

use App\Http\Presenters\Inventory\InventoryPresenter;
use App\Http\Requests\Inventory\InventoryRequest;
use App\Models\Inventory;
use App\Processors\Processor;

class InventoryVariantProcessor extends Processor
{
    /**
     * @var Inventory
     */
    protected $inventory;

    /**
     * @var InventoryPresenter
     */
    protected $presenter;

    /**
     * Constructor.
     *
     * @param Inventory          $inventory
     * @param InventoryPresenter $presenter
     */
    public function __construct(Inventory $inventory, InventoryPresenter $presenter)
    {
        $this->inventory = $inventory;
        $this->presenter = $presenter;
    }

    /**
     * Displays the form for creating a variant for the specified inventory item.
     *
     * @param int|string $itemId
     *
     * @return \Illuminate\View\View
     */
    public function create($itemId)
    {
        $item = $this->inventory->findOrFail($itemId);

        $form = $this->presenter->form($item, $variant = true);

        return view('inventory.variants.create', compact('form'));
    }

    /**
     * Creates a variant of the specified inventory item.
     *
     * @param InventoryRequest $request
     * @param int|string       $itemId
     *
     * @return bool
     */
    public function store(InventoryRequest $request, $itemId)
    {
        $item = $this->inventory->findOrFail($itemId);

        $variant = $item->newVariant();

        $variant->name = $request->input('name', $item->name);
        $variant->category_id = $request->input('category', $item->category_id);
        $variant->metric_id = $request->input('metric', $item->metric_id);

        return $variant->save();
    }
}


<?php

namespace App\Processors\WorkOrder;

use App\Exceptions\WorkOrder\ReportExistsException;
use App\Http\Presenters\WorkOrder\WorkOrderReportPresenter;
use App\Http\Requests\WorkOrder\ReportRequest;
use App\Jobs\WorkOrder\Report\Store;
use App\Models\WorkOrder;
use App\Models\WorkOrderReport;
use App\Processors\Processor;

class WorkOrderReportProcessor extends Processor
{
    /**
     * @var WorkOrder
     */
    protected $workOrder;

    /**
     * @var WorkOrderReport
     */
    protected $report;

    /**
     * @var WorkOrderReportPresenter
     */
    protected $presenter;

    /**
     * Constructor.
     *
     * @param WorkOrder                $workOrder
     * @param WorkOrderReport          $report
     * @param WorkOrderReportPresenter $presenter
     */
    public function __construct(WorkOrder $workOrder, WorkOrderReport $report, WorkOrderReportPresenter $presenter)
    {
        $this->workOrder = $workOrder;
        $this->report = $report;
        $this->presenter = $presenter;
    }

    /**
     * Displays the form for creating a work order report.
     *
     * @param int|string $workOrderId
     *
     * @throws ReportExistsException
     *
     * @return \Illuminate\View\View
     */
    public function create($workOrderId)
    {
        $workOrder = $this->workOrder->findOrFail($workOrderId);

        if ($workOrder->isComplete()) {
            throw new ReportExistsException();
        }

        $form = $this->presenter->form($workOrder, $this->report);

        return view('work-orders.report.create', compact('form'));
    }

    /**
     * Creates a new work order report.
     *
     * @param ReportRequest $request
     * @param int|string    $workOrderId
     *
     * @return bool
     */
    public function store(ReportRequest $request, $workOrderId)
    {
        $workOrder = $this->workOrder->findOrFail($workOrderId);

        $report = $this->report->newInstance();

        return $this->dispatch(new Store($request, $workOrder, $report));
    }

    public function show($workOrderId, $reportId)
    {
        $workOrder = $this->workOrder->findOrFail($workOrderId);

        $report = $workOrder->report()->findOrFail($reportId);

        return view('work-orders.report', compact('workOrder', 'report'));
    }

    public function edit($workOrderId, $reportId)
    {
        //
    }

    public function update($workOrderId, $reportId)
    {
        //
    }

    public function destroy($workOrderId, $reportId)
    {
        //
    }
}


<?php

namespace App\Http\Presenters\WorkOrder;

use App\Http\Presenters\Presenter;
use App\Models\Asset;
use App\Models\Category;
use App\Models\Comment;
use App\Models\Location;
use App\Models\Priority;
use App\Models\Status;
use App\Models\WorkOrder;
use Illuminate\Database\Eloquent\Builder;
use Orchestra\Contracts\Html\Form\Fieldset;
use Orchestra\Contracts\Html\Form\Grid as FormGrid;
use Orchestra\Contracts\Html\Table\Column;
use Orchestra\Contracts\Html\Table\Grid as TableGrid;

class WorkOrderPresenter extends Presenter
{
    /**
     * Returns a new table of all work orders.
     *
     * @param WorkOrder|Builder $workOrder
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function table($workOrder)
    {
        return $this->table->of('work-orders', function (TableGrid $table) use ($workOrder) {
            $table->with($workOrder)->paginate($this->perPage);

            $table->attributes([
                'class' => 'table table-hover table-striped',
            ]);

            $table->column('ID', 'id');

            $table->column('subject', function (Column $column) {
                $column->value = function (WorkOrder $workOrder) {
                    return link_to_route('maintenance.work-orders.show', $workOrder->subject, [$workOrder->getKey()]);
                };
            });

            $table->column('Created At', 'created_at');

            $table->column('created_by', function (Column $column) {
                $column->value = function (WorkOrder $workOrder) {
                    return $workOrder->user->fullname;
                };
            });

            $table->column('priority', function (Column $column) {
                $column->value = function (WorkOrder $workOrder) {
                    if ($workOrder->priority instanceof Priority) {
                        return $workOrder->priority->getLabel();
                    }

                    return HTML::create('em', 'None');
                };
            });

            $table->column('status', function (Column $column) {
                $column->value = function (WorkOrder $workOrder) {
                    if ($workOrder->status instanceof Status) {
                        return $workOrder->status->getLabel();
                    }

                    return HTML::create('em', 'None');
                };
            });
        });
    }

    /**
     * Returns a new table of all work orders assigned to the current user.
     *
     * @param WorkOrder|Builder $workOrder
     *
     * @return Builder
     */
    public function tableAssigned($workOrder)
    {
        $workOrder = $workOrder->whereHas('assignments', function (Builder $query) {
            $query->where('to_user_id', auth()->id());
        });

        return $this->table($workOrder);
    }

    /**
     * Displays a table of all unique sessions on the specified work order.
     *
     * @param WorkOrder $workOrder
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function tableSessions(WorkOrder $workOrder)
    {
        $presenter = new WorkOrderSessionPresenter($this->form, $this->table);

        return $presenter->tablePerWorker($workOrder);
    }

    /**
     * Returns a new form for work orders.
     *
     * @param WorkOrder $workOrder
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function form(WorkOrder $workOrder)
    {
        return $this->form->of('work-orders', function (FormGrid $form) use ($workOrder) {
            if ($workOrder->exists) {
                $method = 'PATCH';
                $url = route('maintenance.work-orders.update', [$workOrder->getKey()]);
                $form->submit = 'Save';
            } else {
                $method = 'POST';
                $url = route('maintenance.work-orders.store');
                $form->submit = 'Create';
            }

            $form->with($workOrder);

            $form->attributes(compact('method', 'url'));

            $form->fieldset(function (Fieldset $fieldset) {
                $fieldset
                    ->control('select', 'category')
                    ->value(function (WorkOrder $workOrder) {
                        return $workOrder->category_id;
                    })
                    ->options(function () {
                        return Category::getSelectHierarchy('work-orders');
                    });

                $fieldset
                    ->control('select', 'location')
                    ->value(function (WorkOrder $workOrder) {
                        return $workOrder->location_id;
                    })
                    ->options(function () {
                        return Location::getSelectHierarchy();
                    });

                $fieldset
                    ->control('select', 'status')
                    ->options(function () {
                        $statuses = Status::all()->pluck('name', 'id');
                        $statuses[0] = 'None';

                        return $statuses;
                    });

                $fieldset
                    ->control('select', 'priority')
                    ->value(function (WorkOrder $workOrder) {
                        return $workOrder->priority_id;
                    })
                    ->options(function () {
                        $priorities = Priority::all()->pluck('name', 'id');
                        $priorities[0] = 'None';

                        return $priorities;
                    });

                $fieldset
                    ->control('select', 'assets[]')
                    ->label('Assets')
                    ->options(function () {
                        return Asset::all()->pluck('name', 'id');
                    })
                    ->attributes([
                        'class'    => 'select2',
                        'multiple' => true,
                    ]);

                $fieldset
                    ->control('input:text', 'subject')
                    ->attributes([
                        'placeholder' => 'ex. Worked on HVAC',
                    ]);

                $fieldset->control('input:textarea', 'description');
            });
        });
    }

    /**
     * Returns a new form for the specified work order comment.
     *
     * @param WorkOrder $workOrder
     * @param Comment   $comment
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function formComment(WorkOrder $workOrder, Comment $comment)
    {
        $presenter = new WorkOrderCommentPresenter($this->form, $this->table);

        return $presenter->form($workOrder, $comment);
    }

    /**
     * Returns a navbar for the work order index.
     *
     * @return \Illuminate\Support\Fluent
     */
    public function navbar()
    {
        return $this->fluent([
            'id'         => 'work-orders',
            'title'      => 'Work Orders',
            'menu'       => view('work-orders._nav'),
            'attributes' => [
                'class' => 'navbar-default',
            ],
        ]);
    }

    /**
     * Returns a navbar for the specified work order.
     *
     * @param WorkOrder $workOrder
     *
     * @return \Illuminate\Support\Fluent
     */
    public function navbarShow(WorkOrder $workOrder)
    {
        return $this->fluent([
            'id'         => 'work-orders-show',
            'title'      => 'Viewing',
            'menu'       => view('work-orders._nav-show', compact('workOrder')),
            'attributes' => [
                'class' => 'navbar-default',
            ],
        ]);
    }

    /**
     * Returns a navbar for the assigned work order index.
     *
     * @return \Illuminate\Support\Fluent
     */
    public function navbarAssigned()
    {
        return $this->fluent([
            'id'         => 'work-orders-assigned',
            'title'      => 'Assigned Work Orders',
            'menu'       => view('work-orders.assigned._nav'),
            'attributes' => [
                'class' => 'navbar-default',
            ],
        ]);
    }
}


<?php

namespace App\Jobs\Attachment;

use App\Http\Requests\AttachmentRequest;
use App\Jobs\Job;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class Store extends Job
{
    /**
     * @var AttachmentRequest
     */
    protected $request;

    /**
     * @var BelongsToMany
     */
    protected $relation;

    /**
     * The storage path to upload files to.
     *
     * @var string
     */
    protected $path = 'files';

    /**
     * Constructor.
     *
     * @param AttachmentRequest $request
     * @param BelongsToMany     $relation
     */
    public function __construct(AttachmentRequest $request, BelongsToMany $relation)
    {
        $this->request = $request;
        $this->relation = $relation;
    }

    /**
     * Uploads and attaches files for the current relation.
     *
     * @param Filesystem $filesystem
     *
     * @return bool|array
     */
    public function handle(Filesystem $filesystem)
    {
        $files = $this->request->file('files');

        if (is_array($files)) {
            $uploaded = [];

            foreach ($files as $file) {
                // Double check that we have an uploaded file instance.
                if ($file instanceof UploadedFile) {
                    // Generates the unique file name.
                    $name = implode('.', [uuid(), $file->getClientOriginalExtension()]);

                    // Generates the complete storage path.
                    $path = implode(DIRECTORY_SEPARATOR, [$this->path, $name]);

                    // Try and move the uploaded file into storage.
                    if ($filesystem->put($path, file_get_contents($file->getRealPath()))) {
                        // Successfully moved uploaded file, create the record.

                        $attributes = [
                            'user_id'   => auth()->id(),
                            'name'      => $file->getClientOriginalName(),
                            'file_name' => $name,
                            'file_path' => $path,
                        ];

                        $uploaded[] = $this->relation->create($attributes);
                    }
                }
            }

            return $uploaded;
        }

        return false;
    }
}


<?php

namespace App\Http\Presenters\Asset;

use App\Http\Presenters\Presenter;
use App\Models\Asset;
use App\Models\Category;
use App\Models\Location;
use Orchestra\Contracts\Html\Form\Fieldset;
use Orchestra\Contracts\Html\Form\Grid as FormGrid;
use Orchestra\Contracts\Html\Table\Column;
use Orchestra\Html\Table\Grid as TableGrid;

class AssetPresenter extends Presenter
{
    /**
     * Returns a new table of all assets.
     *
     * @param Asset $asset
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function table(Asset $asset)
    {
        return $this->table->of('assets', function (TableGrid $table) use ($asset) {
            $table->with($asset)->paginate($this->perPage);

            $table->attributes([
                'class' => 'table table-hover table-striped',
            ]);

            $table->column('tag');

            $table->column('name', function (Column $column) {
                $column->value = function (Asset $asset) {
                    return link_to_route('maintenance.assets.show', $asset->name, [$asset->getKey()]);
                };
            });

            $table->column('category', function (Column $column) {
                $column->value = function (Asset $asset) {
                    return $asset->category->trail;
                };
            });

            $table->column('location', function (Column $column) {
                $column->value = function (Asset $asset) {
                    return $asset->location->trail;
                };
            });

            $table->column('created_at');
        });
    }

    /**
     * Returns a new form for the specified asset.
     *
     * @param Asset $asset
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function form(Asset $asset)
    {
        return $this->form->of('assets', function (FormGrid $form) use ($asset) {
            if ($asset->exists) {
                $method = 'PATCH';
                $route = route('maintenance.assets.update', [$asset->getKey()]);
                $form->submit = 'Save';
            } else {
                $method = 'POST';
                $route = route('maintenance.assets.store');
                $form->submit = 'Create';
            }

            $categories = Category::getSelectHierarchy('assets');
            $locations = Location::getSelectHierarchy();

            $form->resource($this, $route, $asset, compact('method'));

            $form->fieldset(function (Fieldset $fieldset) use ($categories, $locations) {
                $fieldset
                    ->control('input:text', 'tag')
                    ->attributes([
                        'placeholder' => 'ex. 100010',
                    ]);

                $fieldset
                    ->control('input:text', 'name')
                    ->attributes([
                        'placeholder' => 'ex. Ford F150',
                    ]);

                $fieldset
                    ->control('select', 'category')
                    ->options($categories)
                    ->value(function (Asset $asset) {
                        return $asset->category_id;
                    });

                $fieldset
                    ->control('select', 'location')
                    ->options($locations)
                    ->value(function (Asset $asset) {
                        return $asset->location_id;
                    });

                $fieldset->control('input:textarea', 'description');

                $fieldset->control('select', 'condition')
                    ->options(trans('assets.conditions'))
                    ->value(function (Asset $asset) {
                        return $asset->condition_number;
                    });

                $fieldset->control('input:text', 'vendor')
                    ->attributes([
                        'placeholder' => 'ex. Ford',
                    ]);

                $fieldset->control('input:text', 'make')
                    ->attributes([
                        'placeholder' => 'ex. F',
                    ]);

                $fieldset->control('input:text', 'model')
                    ->attributes([
                        'placeholder' => 'ex. 150',
                    ]);

                $fieldset->control('input:text', 'serial')
                    ->attributes([
                        'placeholder' => 'ex. 153423-13432432-2342423',
                    ]);

                $fieldset->control('input:text', 'size')
                    ->attributes([
                        'placeholder' => 'ex. 1905 x 2463',
                    ]);

                $fieldset->control('input:text', 'weight')
                    ->attributes([
                        'placeholder' => 'ex. 1 Ton',
                    ]);

                $fieldset->control('input:text', 'acquired_at')
                    ->attributes([
                        'class'       => 'pickadate',
                        'placeholder' => 'Click to Select a Date',
                    ]);

                $fieldset->control('input:text', 'end_of_life')
                    ->attributes([
                        'class'       => 'pickadate',
                        'placeholder' => 'Click to Select a Date',
                    ]);
            });
        });
    }

    /**
     * Returns a new navbar for the asset index.
     *
     * @return \Illuminate\Support\Fluent
     */
    public function navbar()
    {
        return $this->fluent([
            'id'         => 'assets',
            'title'      => 'Assets',
            'url'        => route('maintenance.assets.index'),
            'menu'       => view('assets._nav'),
            'attributes' => [
                'class' => 'navbar-default',
            ],
        ]);
    }
}


<?php

namespace App\Http\Presenters\Inventory;

use App\Http\Presenters\Presenter;
use App\Models\Category;
use App\Models\Inventory;
use App\Models\Metric;
use Orchestra\Contracts\Html\Form\Fieldset;
use Orchestra\Contracts\Html\Form\Grid as FormGrid;
use Orchestra\Contracts\Html\Table\Column;
use Orchestra\Contracts\Html\Table\Grid as TableGrid;

class InventoryPresenter extends Presenter
{
    /**
     * Returns a table of all inventory items.
     *
     * @param Inventory|\Illuminate\Database\Eloquent\Builder $item
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function table($item)
    {
        return $this->table->of('inventory', function (TableGrid $table) use ($item) {
            $table->with($item)->paginate($this->perPage);

            $table->attributes([
                'class' => 'table table-hover table-striped',
            ]);

            $table->column('ID', 'id');

            $table->column('sku', function (Column $column) {
                $column->label = 'SKU';

                $column->value = function (Inventory $item) {
                    return $item->getSku();
                };
            });

            $table->column('name', function (Column $column) {
                $column->value = function (Inventory $item) {
                    return link_to_route('maintenance.inventory.show', $item->name, [$item->getKey()]);
                };
            });

            $table->column('category', function (Column $column) {
                $column->value = function (Inventory $item) {
                    return $item->category->trail;
                };
            });

            $table->column('current_stock', function (Column $column) {
                $column->value = function (Inventory $item) {
                    return $item->getTotalStock();
                };
            });
        });
    }

    /**
     * Returns a table of all of the specified inventory items variants.
     *
     * @param Inventory|\Illuminate\Database\Eloquent\Builder $item
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function tableVariants($item)
    {
        return $this->table($item->variants());
    }

    /**
     * Returns a table of all inventory items that are not variants.
     *
     * @param int|string $item
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function tableNoVariants($item)
    {
        return $this->table($item->noVariants());
    }

    /**
     * Returns a table of stocks for the specified inventory item.
     *
     * @param Inventory $item
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function tableStocks(Inventory $item)
    {
        return (new InventoryStockPresenter($this->form, $this->table))->table($item);
    }

    /**
     * Returns a new form for creating a new inventory item.
     *
     * @param Inventory  $inventory
     * @param bool|false $variant
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function form(Inventory $inventory, $variant = false)
    {
        return $this->form->of('inventory', function (FormGrid $form) use ($inventory, $variant) {
            if ($inventory->exists) {
                if ($variant === true) {
                    // If the inventory item exists and we're looking to create a form
                    // for a variant, we'll set the forms options accordingly.
                    $method = 'POST';
                    $url = route('maintenance.inventory.variants.store', [$inventory->getKey()]);
                    $form->submit = 'Create';
                } else {
                    // Otherwise we'll set the options to update the specified inventory item.
                    $method = 'PATCH';
                    $url = route('maintenance.inventory.update', [$inventory->getKey()]);
                    $form->submit = 'Save';
                }
            } else {
                $method = 'POST';
                $url = route('maintenance.inventory.store');
                $form->submit = 'Create';
            }

            $form->with($inventory);

            $form->attributes(compact('method', 'url'));

            $categories = Category::getSelectHierarchy('inventories');

            $metrics = Metric::all()->pluck('name', 'id');
            $metrics->put(0, 'None');

            $form->fieldset(function (Fieldset $fieldset) use ($categories, $metrics) {
                $fieldset
                    ->control('select', 'category')
                    ->value(function (Inventory $item) {
                        return $item->category_id;
                    })
                    ->options($categories);

                $fieldset
                    ->control('select', 'metric')
                    ->value(function (Inventory $item) {
                        return $item->metric_id;
                    })
                    ->options($metrics);

                $fieldset
                    ->control('input:text', 'name')
                    ->attributes([
                        'placeholder' => 'ex. Nails',
                    ]);

                $fieldset->control('input:textarea', 'description');
            });
        });
    }

    /**
     * Returns a new navbar for the inventory index.
     *
     * @return \Illuminate\Support\Fluent
     */
    public function navbar()
    {
        return $this->fluent([
            'id'         => 'inventory',
            'title'      => 'Inventory',
            'url'        => route('maintenance.inventory.index'),
            'menu'       => view('inventory._nav'),
            'attributes' => [
                'class' => 'navbar-default',
            ],
        ]);
    }

    /**
     * Returns a new navbar for the specified inventory profile.
     *
     * @param Inventory $item
     *
     * @return \Illuminate\Support\Fluent
     */
    public function navbarProfile(Inventory $item)
    {
        return $this->fluent([
            'id'         => 'inventory-profile',
            'title'      => 'Profile',
            'menu'       => view('inventory._nav-profile', compact('item')),
            'attributes' => [
                'class' => 'navbar-default',
            ],
        ]);
    }

    /**
     * Returns a new navbar for the inventory index.
     *
     * @param Inventory $item
     *
     * @return \Illuminate\Support\Fluent
     */
    public function navbarVariants(Inventory $item)
    {
        return $this->fluent([
            'id'         => 'inventory-variants',
            'title'      => 'Item Variants',
            'menu'       => view('inventory.variants._nav', compact('item')),
            'attributes' => [
                'class' => 'navbar-default',
            ],
        ]);
    }

    /**
     * Returns a new navbar for the inventory stocks index.
     *
     * @param Inventory $item
     *
     * @return \Illuminate\Support\Fluent
     */
    public function navbarStocks(Inventory $item)
    {
        return (new InventoryStockPresenter($this->form, $this->table))->navbar($item);
    }
}


<?php

namespace App\Http\Controllers\WorkOrder;

use App\Http\Controllers\Controller;
use App\Http\Requests\AttachmentRequest;
use App\Http\Requests\AttachmentUpdateRequest;
use App\Processors\WorkOrder\WorkOrderAttachmentProcessor;

class WorkOrderAttachmentController extends Controller
{
    /**
     * @var WorkOrderAttachmentProcessor
     */
    protected $processor;

    /**
     * Constructor.
     *
     * @param WorkOrderAttachmentProcessor $processor
     */
    public function __construct(WorkOrderAttachmentProcessor $processor)
    {
        $this->processor = $processor;
    }

    /**
     * Displays a list of the work order attachments.
     *
     * @param int|string $workOrderId
     *
     * @return \Illuminate\View\View
     */
    public function index($workOrderId)
    {
        return $this->processor->index($workOrderId);
    }

    /**
     * Displays the form to create work order attachments.
     *
     * @param int|string $workOrderId
     *
     * @return \Illuminate\View\View
     */
    public function create($workOrderId)
    {
        return $this->processor->create($workOrderId);
    }

    /**
     * Processes storing the attachment record.
     *
     * @param AttachmentRequest $request
     * @param int|string        $workOrderId
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store(AttachmentRequest $request, $workOrderId)
    {
        if ($uploaded = $this->processor->store($request, $workOrderId)) {
            $count = (is_array($uploaded) ? count($uploaded) : 0);

            flash()->success('Success!', "Successfully uploaded $count file(s).");

            return redirect()->route('maintenance.work-orders.attachments.index', [$workOrderId]);
        } else {
            flash()->error('Error!', 'There was an issue uploading the files you selected. Please try again.');

            return redirect()->route('maintenance.work-orders.attachments.create', [$workOrderId]);
        }
    }

    /**
     * Displays the uploaded file with it's information.
     *
     * @param int|string $workOrderId
     * @param int|string $attachmentId
     *
     * @return \Illuminate\View\View
     */
    public function show($workOrderId, $attachmentId)
    {
        return $this->processor->show($workOrderId, $attachmentId);
    }

    /**
     * Displays the form for editing an uploaded file.
     *
     * @param int|string $workOrderId
     * @param int|string $attachmentId
     *
     * @return \Illuminate\View\View
     */
    public function edit($workOrderId, $attachmentId)
    {
        return $this->processor->edit($workOrderId, $attachmentId);
    }

    /**
     * Updates the specified ticket upload.
     *
     * @param AttachmentUpdateRequest $request
     * @param int|string              $workOrderId
     * @param int|string              $attachmentId
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(AttachmentUpdateRequest $request, $workOrderId, $attachmentId)
    {
        if ($this->processor->update($request, $workOrderId, $attachmentId)) {
            flash()->success('Success!', 'Successfully updated attachment.');

            return redirect()->route('maintenance.work-orders.attachments.show', [$workOrderId, $attachmentId]);
        } else {
            flash()->error('Error!', 'There was an issue updating this attachment. Please try again.');

            return redirect()->route('maintenance.work-orders.attachments.edit', [$workOrderId, $attachmentId]);
        }
    }

    /**
     * Processes deleting an attachment record and the file itself.
     *
     * @param int|string $workOrderId
     * @param int|string $attachmentId
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function destroy($workOrderId, $attachmentId)
    {
        if ($this->processor->destroy($workOrderId, $attachmentId)) {
            flash()->success('Success!', 'Successfully deleted attachment.');

            return redirect()->route('maintenance.work-orders.attachments.index', [$workOrderId]);
        } else {
            flash()->error('Error!', 'There was an issue deleting this attachment. Please try again.');

            return redirect()->route('maintenance.work-orders.attachments.show', [$workOrderId, $attachmentId]);
        }
    }

    /**
     * Prompts the user to download the specified uploaded file.
     *
     * @param int|string $workOrderId
     * @param int|string $attachmentId
     *
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
     */
    public function download($workOrderId, $attachmentId)
    {
        return $this->processor->download($workOrderId, $attachmentId);
    }
}


<?php

namespace App\Jobs\WorkOrder\Part;

use App\Http\Requests\WorkOrder\PartReturnRequest;
use App\Jobs\Job;
use App\Models\InventoryStock;
use App\Models\WorkOrder;
use Illuminate\Database\Eloquent\Relations\Pivot;

class Put extends Job
{
    /**
     * @var PartReturnRequest
     */
    protected $request;

    /**
     * @var WorkOrder
     */
    protected $workOrder;

    /**
     * @var InventoryStock
     */
    protected $stock;

    /**
     * Constructor.
     *
     * @param PartReturnRequest $request
     * @param WorkOrder         $workOrder
     * @param InventoryStock    $stock
     */
    public function __construct(PartReturnRequest $request, WorkOrder $workOrder, InventoryStock $stock)
    {
        $this->request = $request;
        $this->workOrder = $workOrder;
        $this->stock = $stock;
    }

    /**
     * Execute the job.
     *
     * @return bool
     */
    public function handle()
    {
        // Get the requested quantity to return
        $quantity = $this->request->input('quantity');

        // We'll double check that the stock model we've been given contains
        // the pivot attribute, indicating it's been retrieved
        // from the work order.
        if ($this->stock->pivot instanceof Pivot) {
            if ($quantity > $this->stock->pivot->quantity) {
                // If the quantity entered is greater than the
                // taken stock, we'll return all of the stock.
                $returnQuantity = $this->stock->pivot->quantity;
            } else {
                // Otherwise we can use the users quantity input.
                $returnQuantity = $quantity;
            }

            // Set the stock put reason.
            $reason = link_to_route('maintenance.work-orders.show', 'Put Back from Work Order', [$this->workOrder->getKey()]);

            // Return the specified quantity.
            $this->stock->put($returnQuantity, $reason);

            // Retrieve the left over quantity for the work order.
            $newQuantity = $this->stock->pivot->quantity - $returnQuantity;

            if ($newQuantity == 0) {
                // If the new quantity is zero, we'll detach the
                // stock record from the work order parts.
                $this->workOrder->parts()->detach($this->stock->getKey());
            } else {
                // Otherwise we'll update the quantity on the pivot record.
                $this->workOrder->parts()->updateExistingPivot($this->stock->getKey(), ['quantity' => $newQuantity]);
            }

            return true;
        }

        return false;
    }
}


<?php

namespace App\Jobs\WorkOrder\Session;

use App\Jobs\Job;
use App\Models\WorkOrder;

class End extends Job
{
    /**
     * @var WorkOrder
     */
    protected $workOrder;

    /**
     * Constructor.
     *
     * @param WorkOrder $workOrder
     */
    public function __construct(WorkOrder $workOrder)
    {
        $this->workOrder = $workOrder;
    }

    /**
     * Execute the job.
     *
     * @return bool
     */
    public function handle()
    {
        $session = $this->workOrder->getLastUsersSession(auth()->id());

        $session->out = $session->freshTimestamp();

        return $session->save();
    }
}


<?php

namespace App\Http\Presenters;

use App\Models\Metric;
use Orchestra\Contracts\Html\Form\Fieldset;
use Orchestra\Contracts\Html\Form\Grid as FormGrid;
use Orchestra\Contracts\Html\Table\Grid as TableGrid;

class MetricPresenter extends Presenter
{
    /**
     * Returns a new table of all metrics.
     *
     * @param Metric $metric
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function table(Metric $metric)
    {
        return $this->table->of('metrics', function (TableGrid $table) use ($metric) {
            $table->with($metric)->paginate($this->perPage);

            $table->column('name');
            $table->column('symbol');
            $table->column('Created', 'created_at');
        });
    }

    /**
     * Returns a new form for the specified metric.
     *
     * @param Metric $metric
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function form(Metric $metric)
    {
        return $this->form->of('metrics', function (FormGrid $form) use ($metric) {
            if ($metric->exists) {
                $method = 'PATCH';
                $url = route('maintenance.metrics.update', [$metric->getKey()]);
                $form->submit = 'Save';
            } else {
                $method = 'POST';
                $url = route('maintenance.metrics.store');
                $form->submit = 'Create';
            }

            $form->attributes(compact('method', 'url'));

            $form->with($metric);

            $form->fieldset(function (Fieldset $fieldset) {
                $fieldset
                    ->control('input:text', 'name')
                    ->attributes([
                        'placeholder' => 'ex. Tonnes, Pounds, Grams',
                    ]);

                $fieldset
                    ->control('input:text', 'symbol')
                    ->attributes([
                        'placeholder' => 'ex. T, LBS, G',
                    ]);
            });
        });
    }

    /**
     * Returns a new navbar for the metric index.
     *
     * @return \Illuminate\Support\Fluent
     */
    public function navbar()
    {
        return $this->fluent([
            'id'         => 'metrics',
            'title'      => 'Metrics',
            'menu'       => view('metrics._nav'),
            'attributes' => [
                'class' => 'navbar-default',
            ],
        ]);
    }
}


<?php

namespace App\Http\Presenters;

use App\Models\Revision;
use App\Models\User;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Fluent;
use Orchestra\Contracts\Html\Form\Factory as FormFactory;
use Orchestra\Contracts\Html\Form\Grid as FormGrid;
use Orchestra\Contracts\Html\Form\Presenter as PresenterContract;
use Orchestra\Contracts\Html\Table\Column;
use Orchestra\Contracts\Html\Table\Factory as TableFactory;
use Orchestra\Contracts\Html\Table\Grid as TableGrid;
use Orchestra\Support\Facades\HTML;

abstract class Presenter implements PresenterContract
{
    /**
     * Implementation of form contract.
     *
     * @var \Orchestra\Contracts\Html\Form\Factory
     */
    protected $form;

    /**
     * Implementation of table contract.
     *
     * @var \Orchestra\Contracts\Html\Table\Factory
     */
    protected $table;

    /**
     * The default amount of records to display per page.
     *
     * @var int
     */
    protected $perPage = 10;

    /**
     * Constructor.
     *
     * @param FormFactory  $form
     * @param TableFactory $table
     */
    public function __construct(FormFactory $form, TableFactory $table)
    {
        $this->form = $form;
        $this->table = $table;
    }

    /**
     * Returns a new Fluent instance.
     *
     * @param array $attributes
     *
     * @return Fluent
     */
    public function fluent(array $attributes = [])
    {
        return new Fluent($attributes);
    }

    /**
     * Handles the form action URL.
     *
     * @param string $url
     *
     * @return string
     */
    public function handles($url)
    {
        return $url;
    }

    /**
     * {@inheritdoc}
     */
    public function setupForm(FormGrid $form)
    {
        $form->layout('components.form');
    }

    /**
     * Returns a new table of all revisions.
     *
     * @param string    $for
     * @param MorphMany $revisions
     *
     * @return \Orchestra\Contracts\Html\Builder
     */
    public function tableHistory($for, MorphMany $revisions)
    {
        return $this->table->of("$for.revisions", function (TableGrid $table) use ($revisions) {
            $table->with($revisions)->paginate($this->perPage);

            $table->pageName = 'history';

            $table->column('user_responsible', function (Column $column) {
                $column->value = function (Revision $revision) {
                    $user = $revision->getUserResponsible();

                    if ($user instanceof User) {
                        return $user->getRecipientName();
                    }

                    return HTML::create('em', 'None');
                };
            });

            $table->column('changed', function (Column $column) {
                $column->value = function (Revision $revision) {
                    return $revision->getColumnName();
                };
            });

            $table->column('from', function (Column $column) {
                $column->value = function (Revision $revision) {
                    $old = $revision->getOldValue();

                    if (is_null($old)) {
                        return HTML::create('em', 'None');
                    }

                    return $old;
                };
            });

            $table->column('to', function (Column $column) {
                $column->value = function (Revision $revision) {
                    $new = $revision->getNewValue();

                    if (is_null($new)) {
                        return HTML::create('em', 'None');
                    }

                    return $new;
                };
            });

            $table->column('On', 'created_at');
        });
    }
}


<?php

namespace App\Http\Controllers\Asset;

use App\Http\Controllers\Controller as BaseController;
use App\Http\Requests\Asset\ImageRequest;
use App\Http\Requests\AttachmentUpdateRequest;
use App\Repositories\Asset\ImageRepository;
use App\Repositories\Asset\Repository as AssetRepository;

class ImageController extends BaseController
{
    /**
     * @var AssetRepository
     */
    protected $asset;

    /**
     * @var ImageRepository
     */
    protected $image;

    /**
     * Constructor.
     *
     * @param AssetRepository $asset
     * @param ImageRepository $image
     */
    public function __construct(AssetRepository $asset, ImageRepository $image)
    {
        $this->asset = $asset;
        $this->image = $image;
    }

    /**
     * Displays all images attached to the specified asset.
     *
     * @param int|string $id
     *
     * @return \Illuminate\View\View
     */
    public function index($id)
    {
        $asset = $this->asset->find($id);

        return view('assets.images.index', compact('asset'));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @param int|string $assetId
     *
     * @return \Illuminate\View\View
     */
    public function create($assetId)
    {
        $asset = $this->asset->find($assetId);

        return view('assets.images.create', compact('asset'));
    }

    /**
     * Uploads images and attaches them to the specified asset.
     *
     * @param ImageRequest $request
     * @param int|string   $id
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store(ImageRequest $request, $id)
    {
        $asset = $this->asset->find($id);

        $attachments = $this->image->upload($request, $asset, $asset->images());

        if ($attachments) {
            $message = 'Successfully uploaded files.';

            return redirect()->route('maintenance.assets.images.index', [$asset->id])->withSuccess($message);
        } else {
            $message = 'There was an issue uploading the files you selected. Please try again.';

            return redirect()->route('maintenance.assets.images.create', [$id])->withErrors($message);
        }
    }

    /**
     * Displays the asset image.
     *
     * @param int|string $id
     * @param int|string $imageId
     *
     * @return \Illuminate\View\View
     */
    public function show($id, $imageId)
    {
        $asset = $this->asset->find($id);

        $image = $asset->images()->find($imageId);

        if ($image) {
            return view('assets.images.show', compact('asset', 'image'));
        }

        abort(404);
    }

    /**
     * Displays the form for editing an uploaded image.
     *
     * @param int|string $id
     * @param int|string $imageId
     *
     * @return \Illuminate\View\View
     */
    public function edit($id, $imageId)
    {
        $asset = $this->asset->find($id);

        $image = $asset->images()->find($imageId);

        if ($image) {
            return view('assets.images.edit', compact('asset', 'image'));
        }

        abort(404);
    }

    /**
     * Updates the specified asset image upload.
     *
     * @param AttachmentUpdateRequest $request
     * @param int|string              $id
     * @param int|string              $imageId
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(AttachmentUpdateRequest $request, $id, $imageId)
    {
        $asset = $this->asset->find($id);

        $image = $this->image->update($request, $asset->images(), $imageId);

        if ($image) {
            $message = 'Successfully updated image.';

            return redirect()->route('maintenance.assets.images.show', [$asset->id, $image->id])->withSuccess($message);
        } else {
            $message = 'There was an issue updating this image. Please try again.';

            return redirect()->route('maintenance.assets.images.show', [$id, $imageId])->withErrors($message);
        }
    }

    /**
     * Processes deleting an attachment record and the file itself.
     *
     * @param int|string $id
     * @param int|string $imageId
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function destroy($id, $imageId)
    {
        $asset = $this->asset->find($id);

        $image = $asset->images()->find($imageId);

        if ($image && $image->delete()) {
            $message = 'Successfully deleted attachment.';

            return redirect()->route('maintenance.assets.images.index', [$asset->id])->withSuccess($message);
        } else {
            $message = 'There was an issue deleting this attachment. Please try again.';

            return redirect()->route('maintenance.assets.images.show', [$asset->id, $image->id])->withErrors($message);
        }
    }

    /**
     * Prompts the user to download the specified uploaded file.
     *
     * @param int|string $id
     * @param int|string $imageId
     *
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
     */
    public function download($id, $imageId)
    {
        $asset = $this->asset->find($id);

        $image = $asset->images()->find($imageId);

        if ($image) {
            return response()->download($image->download_path);
        }

        abort(404);
    }
}


<?php

namespace App\Processors;

use App\Http\Presenters\MetricPresenter;
use App\Http\Requests\MetricRequest;
use App\Jobs\Metric\Store;
use App\Jobs\Metric\Update;
use App\Models\Metric;

class MetricProcessor extends Processor
{
    /**
     * @var Metric
     */
    protected $metric;

    /**
     * @var MetricPresenter
     */
    protected $presenter;

    /**
     * Constructor.
     *
     * @param Metric          $metric
     * @param MetricPresenter $presenter
     */
    public function __construct(Metric $metric, MetricPresenter $presenter)
    {
        $this->metric = $metric;
        $this->presenter = $presenter;
    }

    /**
     * Displays all metrics.
     *
     * @return \Illuminate\View\View
     */
    public function index()
    {
        $metrics = $this->presenter->table($this->metric);

        $navbar = $this->presenter->navbar();

        return view('metrics.index', compact('metrics', 'navbar'));
    }

    /**
     * Displays the form for creating a new metric.
     *
     * @return \Illuminate\View\View
     */
    public function create()
    {
        $form = $this->presenter->form($this->metric);

        return view('metrics.create', compact('form'));
    }

    /**
     * Creates a new metric.
     *
     * @param MetricRequest $request
     *
     * @return mixed
     */
    public function store(MetricRequest $request)
    {
        $metric = $this->metric->newInstance();

        return $this->dispatch(new Store($request, $metric));
    }

    /**
     * Displays the specified metric.
     *
     * @param int|string $id
     *
     * @return \Illuminate\View\View
     */
    public function show($id)
    {
        $metric = $this->metric->findOrFail($id);

        return view('metrics.show', compact('metric'));
    }

    /**
     * Displays the form for editing the specified metric.
     *
     * @param int|string $id
     *
     * @return \Illuminate\View\View
     */
    public function edit($id)
    {
        $metric = $this->metric->findOrFail($id);

        $form = $this->presenter->form($metric);

        return view('metrics.edit', compact('form'));
    }

    public function update(MetricRequest $request, $id)
    {
        $metric = $this->metric->findOrFail($id);

        return $this->dispatch(new Update($request, $metric));
    }

    /**
     * Deletes the specified metric.
     *
     * @param int|string $id
     *
     * @return bool
     */
    public function destroy($id)
    {
        $metric = $this->metric->findOrFail($id);

        return $metric->delete();
    }
}


<?php

namespace App\Processors\Asset;

use App\Http\Presenters\Asset\AssetPresenter;
use App\Http\Requests\Asset\AssetRequest;
use App\Models\Asset;
use App\Processors\Processor;
use Illuminate\Contracts\Auth\Guard;

class AssetProcessor extends Processor
{
    /**
     * @var Asset
     */
    protected $asset;

    /**
     * @var Guard
     */
    protected $guard;

    /**
     * @var AssetPresenter
     */
    protected $presenter;

    /**
     * Constructor.
     *
     * @param Asset          $asset
     * @param Guard          $guard
     * @param AssetPresenter $presenter
     */
    public function __construct(Asset $asset, Guard $guard, AssetPresenter $presenter)
    {
        $this->asset = $asset;
        $this->guard = $guard;
        $this->presenter = $presenter;
    }

    /**
     * Displays all assets.
     *
     * @return \Illuminate\View\View
     */
    public function index()
    {
        $navbar = $this->presenter->navbar();

        $assets = $this->presenter->table($this->asset);

        return view('assets.index', compact('assets', 'navbar'));
    }

    /**
     * Displays the form for creating assets.
     *
     * @return \Illuminate\View\View
     */
    public function create()
    {
        $form = $this->presenter->form($this->asset);

        return view('assets.create', compact('form'));
    }

    /**
     * Creates a new asset.
     *
     * @param AssetRequest $request
     *
     * @return bool
     */
    public function store(AssetRequest $request)
    {
        $asset = $this->asset->newInstance();

        $asset->user_id = $this->guard->id();
        $asset->tag = $request->input('tag');
        $asset->category_id = $request->input('category');
        $asset->location_id = $request->input('location');
        $asset->name = $request->input('name');
        $asset->condition = $request->input('condition');
        $asset->vendor = $request->input('vendor');
        $asset->make = $request->input('make');
        $asset->model = $request->input('model');
        $asset->size = $request->input('size');
        $asset->weight = $request->input('weight');
        $asset->serial = $request->input('serial');
        $asset->acquired_at = $request->formatDateWithTime($request->input('acquired_at'));
        $asset->end_of_life = $request->formatDateWithTime($request->input('end_of_life'));

        return $asset->save();
    }

    /**
     * Displays the specified asset.
     *
     * @param int|string $id
     *
     * @return \Illuminate\View\View
     */
    public function show($id)
    {
        $asset = $this->asset->findOrFail($id);

        return view('assets.show', compact('asset'));
    }

    /**
     * Displays the form for editing the specified asset.
     *
     * @param int|string $id
     *
     * @return \Illuminate\View\View
     */
    public function edit($id)
    {
        $asset = $this->asset->findOrFail($id);

        $form = $this->presenter->form($asset);

        return view('assets.edit', compact('form'));
    }

    /**
     * Updates the specified asset.
     *
     * @param AssetRequest $request
     * @param int|string   $id
     *
     * @return bool
     */
    public function update(AssetRequest $request, $id)
    {
        $asset = $this->asset->findOrFail($id);

        $asset->tag = $request->input('tag');
        $asset->category_id = $request->input('category');
        $asset->location_id = $request->input('location');
        $asset->name = $request->input('name');
        $asset->condition = $request->input('condition');
        $asset->vendor = $request->input('vendor');
        $asset->make = $request->input('make');
        $asset->model = $request->input('model');
        $asset->size = $request->input('size');
        $asset->weight = $request->input('weight');
        $asset->serial = $request->input('serial');
        $asset->acquired_at = $request->formatDateWithTime($request->input('acquired_at'));
        $asset->end_of_life = $request->formatDateWithTime($request->input('end_of_life'));

        return $asset->save();
    }

    /**
     * Deletes the specified asset.
     *
     * @param int|string $id
     *
     * @return bool
     */
    public function destroy($id)
    {
        $asset = $this->asset->findOrFail($id);

        return $asset->delete();
    }
}


<?php

namespace App\Jobs\Attachment;

use App\Http\Requests\AttachmentUpdateRequest;
use App\Jobs\Job;
use App\Models\Attachment;

class Update extends Job
{
    /**
     * @var AttachmentUpdateRequest
     */
    protected $request;

    /**
     * @var Attachment
     */
    protected $attachment;

    /**
     * Constructor.
     *
     * @param AttachmentUpdateRequest $request
     * @param Attachment              $attachment
     */
    public function __construct(AttachmentUpdateRequest $request, Attachment $attachment)
    {
        $this->request = $request;
        $this->attachment = $attachment;
    }

    /**
     * Execute the job.
     *
     * @return bool
     */
    public function handle()
    {
        $this->attachment->name = $this->request->input('name', $this->attachment->name);

        return $this->attachment->save();
    }
}


<?php

namespace App\Models\Traits;

trait HasScopeIdTrait
{
    /**
     * Allows all tables extending from the base model to be scoped by ID.
     *
     * @param object      $query
     * @param int /string $id
     *
     * @return object
     */
    public function scopeId($query, $id = null)
    {
        if (!is_null($id)) {
            $query->where('id', $id);
        }

        return $query;
    }
}


<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Response;
use Orchestra\Routing\Controller as BaseController;
use Orchestra\Routing\Traits\ControllerResponseTrait;
use Stevebauman\Purify\Facades\Purify;

abstract class Controller extends BaseController
{
    use AuthorizesRequests, ControllerResponseTrait, DispatchesJobs, ValidatesRequests;

    /**
     * Stores the URL to redirect to.
     *
     * @var string
     */
    protected $redirect;

    /**
     * Stores the message to display to the user.
     *
     * @var string
     */
    protected $message;

    /**
     * Stores the type of message that is displayed to the user.
     *
     * @var string
     */
    protected $messageType;

    /**
     * Holds validator errors, either array or json string.
     *
     * @var array|string
     */
    protected $errors;

    /**
     * Asks the request if it's ajax or not.
     *
     * @return bool
     */
    public function isAjax()
    {
        return Request::ajax();
    }

    /**
     * Returns the proper response to user. If the request was made from ajax, then an json response is sent.
     * If a request is a typical request without ajax, a user is sent a redirect with session flash messages.
     *
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
     */
    public function response()
    {
        if ($this->isAjax()) {
            if ($this->errors) {
                return $this->responseJson([
                    'errors' => $this->errors,
                ]);
            } else {
                return $this->responseJson([
                    'message'     => $this->message,
                    'messageType' => $this->messageType,
                    'redirect'    => $this->redirect,
                ]);
            }
        } else {
            if ($this->errors) {
                return redirect($this->redirect)
                    ->withInput()
                    ->withErrors($this->errors);
            } else {
                return redirect($this->redirect)
                    ->withInput()
                    ->with('message', $this->message)
                    ->with('messageType', $this->messageType);
            }
        }
    }

    /**
     * Returns a JSON response to the client.
     *
     * @param array $data
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function responseJson($data)
    {
        return Response::json($data);
    }

    /**
     * Returns input from the client. If clean is set to true, the input will be
     * ran through the purifier before it is returned.
     *
     * @param string $name
     * @param bool   $clean
     *
     * @return mixed
     */
    protected function input($name, $clean = false)
    {
        if ($this->inputHas($name)) {
            if ($clean) {
                return $this->clean(Input::get($name));
            } else {
                return Input::get($name);
            }
        }

        return;
    }

    /**
     * Returns the specified uploaded file by it's input name.
     *
     * @param string $name
     *
     * @return bool|array|\Symfony\Component\HttpFoundation\File\UploadedFile
     */
    protected function inputFile($name)
    {
        if ($this->inputHasFile($name)) {
            return Input::file($name);
        }

        return false;
    }

    /**
     * Returns all input.
     *
     * @return array
     */
    protected function inputAll()
    {
        return Input::all();
    }

    /**
     * Returns true / false if the current request
     * contains an input field of the specified name.
     *
     * @param string $name
     *
     * @return bool
     */
    protected function inputHas($name)
    {
        return Input::has($name);
    }

    /**
     * Returns true / false if the current request
     * contains an uploaded file field with the
     * specified name.
     *
     * @param string $name
     *
     * @return mixed
     */
    protected function inputHasFile($name)
    {
        return Input::hasFile($name);
    }

    /**
     * Cleans the specified input.
     *
     * @param array|string $input
     *
     * @return array|string
     */
    public function clean($input)
    {
        return Purify::clean($input);
    }
}


<?php

namespace App\Models\Traits;

use Baum\Node;

trait SelectHierarchyTrait
{
    /**
     * Returns the complete nested set table in a nested list.
     *
     * @param string $belongsTo
     *
     * @return array
     */
    public static function getSelectHierarchy($belongsTo = null)
    {
        $query = static::roots();

        if (!is_null($belongsTo)) {
            $query->where('belongs_to', $belongsTo);
        }

        $roots = $query->with('children')->get();

        $options = [0 => 'None'];

        foreach ($roots as $root) {
            $options = $options + static::getRenderedNode($root);
        }

        return $options;
    }

    /**
     * Renders the specified category and it's children in single dimension array.
     *
     * @param Node $node
     *
     * @return array
     */
    public static function getRenderedNode(Node $node)
    {
        $options = [];

        if ($node->isRoot()) {
            $name = $node->name;
        } else {
            $depth = str_repeat('--', $node->depth);

            $name = sprintf('%s %s', $depth, $node->name);
        }

        $options[$node->id] = $name;

        if ($node->children()->count() > 0) {
            foreach ($node->children as $child) {
                $options = $options + static::getRenderedNode($child);
            }
        }

        return $options;
    }
}


<?php

namespace App\Jobs\WorkOrder\Session;

use App\Jobs\Job;
use App\Models\WorkOrder;
use App\Models\WorkOrderSession;

class Start extends Job
{
    /**
     * @var WorkOrder
     */
    protected $workOrder;

    /**
     * Constructor.
     *
     * @param WorkOrder $workOrder
     */
    public function __construct(WorkOrder $workOrder)
    {
        $this->workOrder = $workOrder;
    }

    /**
     * Execute the job.
     *
     * @return bool
     */
    public function handle()
    {
        $session = new WorkOrderSession();

        $session->user_id = auth()->id();
        $session->work_order_id = $this->workOrder->id;
        $session->in = $session->freshTimestamp();

        if ($this->workOrder->sessions->count() === 0 || is_null($this->workOrder->started_at)) {
            $this->workOrder->update(['started_at' => $this->workOrder->freshTimestamp()]);
        }

        return $session->save();
    }
}


<?php

namespace App\Jobs\WorkOrder\Priority;

use App\Http\Requests\WorkOrder\PriorityRequest;
use App\Jobs\Job;
use App\Models\Priority;

class Update extends Job
{
    /**
     * @var PriorityRequest
     */
    protected $request;

    /**
     * @var Priority
     */
    protected $priority;

    /**
     * Constructor.
     *
     * @param PriorityRequest $request
     * @param Priority        $priority
     */
    public function __construct(PriorityRequest $request, Priority $priority)
    {
        $this->request = $request;
        $this->priority = $priority;
    }

    /**
     * Executes the job.
     *
     * @return bool
     */
    public function handle()
    {
        $this->priority->name = $this->request->input('name', $this->priority->name);
        $this->priority->color = $this->request->input('color', $this->priority->color);

        return $this->priority->save();
    }
}


<?php

namespace App\Jobs\WorkOrder;

use App\Http\Requests\WorkOrder\WorkOrderRequest;
use App\Jobs\Job;
use App\Models\WorkOrder;

class Update extends Job
{
    /**
     * @var WorkOrderRequest
     */
    protected $request;

    /**
     * @var WorkOrder
     */
    protected $workOrder;

    /**
     * Constructor.
     *
     * @param WorkOrderRequest $request
     * @param WorkOrder        $workOrder
     */
    public function __construct(WorkOrderRequest $request, WorkOrder $workOrder)
    {
        $this->request = $request;
        $this->workOrder = $workOrder;
    }

    /**
     * Execute the job.
     *
     * @return bool
     */
    public function handle()
    {
        $this->workOrder->category_id = $this->request->input('category');
        $this->workOrder->location_id = $this->request->input('location');
        $this->workOrder->status_id = $this->request->input('status');
        $this->workOrder->priority_id = $this->request->input('priority');
        $this->workOrder->subject = $this->request->input('subject');
        $this->workOrder->description = $this->request->clean($this->request->input('description'));
        $this->workOrder->started_at = $this->request->input('started_at');
        $this->workOrder->completed_at = $this->request->input('completed_at');

        if ($this->workOrder->save()) {
            $assets = $this->request->input('assets', []);

            if (is_array($assets) && count($assets) > 0) {
                $this->workOrder->assets()->sync($assets);
            }

            return true;
        }

        return false;
    }
}


<?php

namespace App\Providers;

use Illuminate\Contracts\View\Factory;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    /**
     * The view composers to register.
     *
     * @var array
     */
    protected $composers = [
        //
    ];

    /**
     * Registers view composers during boot.
     *
     * @param Factory $view
     */
    public function boot(Factory $view)
    {
        foreach ($this->composers as $callback => $views) {
            $view->composer($views, $callback);
        }
    }

    /**
     * Register the service provider.
     */
    public function register()
    {
        //
    }
}


<?php

namespace App\Seeders;

use App\Repositories\MetricRepository;
use App\Services\ConfigService;
use Illuminate\Database\Seeder;

class MetricSeeder extends Seeder
{
    /**
     * @var MetricRepository
     */
    protected $metric;

    /**
     * @var ConfigService
     */
    protected $config;

    /**
     * Constructor.
     *
     * @param MetricRepository $metric
     * @param ConfigService    $config
     */
    public function __construct(MetricRepository $metric, ConfigService $config)
    {
        $this->metric = $metric;
        $this->config = $config->setPrefix('maintenance');
    }

    /**
     * Runs the seeding operations.
     */
    public function run()
    {
        $metrics = $this->getSeedData();

        foreach ($metrics as $metric) {
            $this->metric->model()->create($metric);
        }
    }

    /**
     * Retrieves the seed data from the maintenance configuration.
     *
     * @return mixed
     */
    private function getSeedData()
    {
        return $this->config->get('seed.metrics');
    }
}


<?php

namespace App\Jobs\WorkOrder;

use App\Jobs\Job;
use App\Models\Priority;
use App\Models\Status;
use App\Models\WorkOrder;
use App\Models\WorkRequest;

class StoreFromWorkRequest extends Job
{
    /**
     * @var WorkRequest
     */
    protected $workRequest;

    /**
     * Constructor.
     *
     * @param WorkRequest $workRequest
     */
    public function __construct(WorkRequest $workRequest)
    {
        $this->workRequest = $workRequest;
    }

    /**
     * Execute the job.
     *
     * @return bool
     */
    public function handle()
    {
        // We'll make sure the work request doesn't already have a
        // work order attached to it before we try and create it.
        if (!$this->workRequest->hasWorkOrder()) {
            $priority = Priority::findOrCreateRequested();

            $status = Status::findOrCreateRequested();

            $workOrder = new WorkOrder();

            $workOrder->status_id = $status->getKey();
            $workOrder->priority_id = $priority->getKey();
            $workOrder->request_id = $this->workRequest->getKey();
            $workOrder->user_id = $this->workRequest->user_id;
            $workOrder->subject = $this->workRequest->subject;
            $workOrder->description = $this->workRequest->description;

            if ($workOrder->save()) {
                return $workOrder;
            }
        }

        return false;
    }
}


<?php

namespace App\Jobs\Attachment;

use App\Jobs\Job;
use App\Models\Attachment;
use Illuminate\Contracts\Filesystem\Filesystem;
use League\Flysystem\FileNotFoundException;

class Destroy extends Job
{
    /**
     * @var Attachment
     */
    protected $attachment;

    /**
     * Constructor.
     *
     * @param Attachment $attachment
     */
    public function __construct(Attachment $attachment)
    {
        $this->attachment = $attachment;
    }

    /**
     * Deletes the current attachment as well as the file.
     *
     * @param Filesystem $filesystem
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function handle(Filesystem $filesystem)
    {
        try {
            if ($filesystem->delete($this->attachment->getStorageFilePath())) {
                return $this->attachment->delete();
            }
        } catch (FileNotFoundException $e) {
            //
        }

        return false;
    }
}


<?php

namespace App\Processors\Inventory;

use App\Http\Presenters\Inventory\InventoryStockPresenter;
use App\Http\Requests\Inventory\InventoryStockRequest;
use App\Jobs\Inventory\Stock\Store;
use App\Jobs\Inventory\Stock\Update;
use App\Models\Inventory;
use App\Processors\Processor;

class InventoryStockProcessor extends Processor
{
    /**
     * @var Inventory
     */
    protected $inventory;

    /**
     * @var InventoryStockPresenter
     */
    protected $presenter;

    /**
     * Constructor.
     *
     * @param Inventory               $inventory
     * @param InventoryStockPresenter $presenter
     */
    public function __construct(Inventory $inventory, InventoryStockPresenter $presenter)
    {
        $this->inventory = $inventory;
        $this->presenter = $presenter;
    }

    /**
     * Displays all stocks for the specified inventory item.
     *
     * @param int|string $itemId
     *
     * @return \Illuminate\View\View
     */
    public function index($itemId)
    {
        $item = $this->inventory->findOrFail($itemId);

        $navbar = $this->presenter->navbar($item);

        $stocks = $this->presenter->table($item);

        return view('inventory.stocks.index', compact('stocks', 'navbar'));
    }

    /**
     * Displays the from for creating a stock for.
     *
     * @param int|string $itemId
     *
     * @return \Illuminate\View\View
     */
    public function create($itemId)
    {
        $item = $this->inventory->findOrFail($itemId);

        $form = $this->presenter->form($item, $item->stocks()->getRelated());

        return view('inventory.stocks.create', compact('form'));
    }

    /**
     * Creates a new stock on the specified item.
     *
     * @param InventoryStockRequest $request
     * @param int|string            $itemId
     *
     * @return bool
     */
    public function store(InventoryStockRequest $request, $itemId)
    {
        $item = $this->inventory->findOrFail($itemId);

        $stock = $item->stocks()->getRelated();

        return $this->dispatch(new Store($request, $item, $stock));
    }

    /**
     * Displays the specified items stock.
     *
     * @param int|string $itemId
     * @param int|string $stockId
     *
     * @return \Illuminate\View\View
     */
    public function show($itemId, $stockId)
    {
        $item = $this->inventory->findOrFail($itemId);

        $stock = $item->stocks()->findOrFail($stockId);

        $movements = $this->presenter->tableMovements($item, $stock);

        return view('inventory.stocks.show', compact('item', 'stock', 'movements'));
    }

    /**
     * Displays the form for editing the specified items stock.
     *
     * @param int|string $itemId
     * @param int|string $stockId
     *
     * @return \Illuminate\View\View
     */
    public function edit($itemId, $stockId)
    {
        $item = $this->inventory->findOrFail($itemId);

        $stock = $item->stocks()->findOrFail($stockId);

        $form = $this->presenter->form($item, $stock);

        return view('inventory.stocks.edit', compact('form'));
    }

    /**
     * Updates the specified inventory stock.
     *
     * @param InventoryStockRequest $request
     * @param int|string            $itemId
     * @param int|string            $stockId
     *
     * @return bool
     */
    public function update(InventoryStockRequest $request, $itemId, $stockId)
    {
        $item = $this->inventory->findOrFail($itemId);

        $stock = $item->stocks()->findOrFail($stockId);

        return $this->dispatch(new Update($request, $item, $stock));
    }

    /**
     * Deletes the specified inventory stock.
     *
     * @param int|string $itemId
     * @param int|string $stockId
     *
     * @return bool
     */
    public function destroy($itemId, $stockId)
    {
        $item = $this->inventory->findOrFail($itemId);

        $stock = $item->stocks()->findOrFail($stockId);

        return $stock->delete();
    }
}


<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateAssetManualsTable extends Migration
{
    /**
     * Run the migrations.
     */
    public function up()
    {
        Schema::create('asset_manuals', function (Blueprint $table) {
            $table->integer('asset_id')->unsigned();
            $table->integer('attachment_id')->unsigned();

            $table->foreign('asset_id')->references('id')->on('assets')
                ->onUpdate('restrict')
                ->onDelete('cascade');

            $table->foreign('attachment_id')->references('id')->on('attachments')
                ->onUpdate('restrict')
                ->onDelete('cascade');
        });

        Schema::create('asset_images', function (Blueprint $table) {
            $table->integer('asset_id')->unsigned();
            $table->integer('attachment_id')->unsigned();

            $table->foreign('asset_id')->references('id')->on('assets')
                ->onUpdate('restrict')
                ->onDelete('cascade');

            $table->foreign('attachment_id')->references('id')->on('attachments')
                ->onUpdate('restrict')
                ->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down()
    {
        Schema::drop('asset_images');
        Schema::drop('asset_manuals');
    }
}