] * * @see ComponentsController::getDatatable() method that generates the JSON response * @since [v3.0] * * @return View * * @throws AuthorizationException */ public function index() { $this->authorize('view', Component::class); return view('components/index'); } /** * Returns a form to create a new component. * * @author [A. Gianotto] [] * * @see ComponentsController::postCreate() method that stores the data * @since [v3.0] * * @return View * * @throws AuthorizationException */ public function create() { $this->authorize('create', Component::class); return view('components/edit')->with('category_type', 'component') ->with('item', new Component); } /** * Validate and store data for new component. * * @author [A. Gianotto] [] * * @see ComponentsController::getCreate() method that generates the view * @since [v3.0] * * @return RedirectResponse * * @throws AuthorizationException */ public function store(StoreComponentRequest $request) { $this->authorize('create', Component::class); $component = new Component; $component->name = $request->input('name'); $component->category_id = $request->input('category_id'); $component->manufacturer_id = $request->input('manufacturer_id'); $component->model_number = $request->input('model_number'); $component->location_id = $request->input('location_id'); $component->company_id = Company::getIdForCurrentUser($request->input('company_id')); // order_number / supplier_id / purchase_date / purchase_cost all // moved off the parent column to Orders / OrderItems. $component->min_amt = $request->input('min_amt', null); $component->serial = $request->input('serial', null); $component->qty = $request->input('qty'); $component->created_by = auth()->id(); $component->notes = $request->input('notes'); // Seed the template supplier from the initial-acquisition // supplier on the create form; editable afterwards. $component->default_supplier_id = $request->input('default_supplier_id', $request->input('supplier_id')); $component = $request->handleImages($component); if ($request->input('redirect_option') === 'back') { session()->put(['redirect_option' => 'index']); } else { session()->put(['redirect_option' => $request->input('redirect_option')]); } if ($component->save()) { $this->enrichInitialOrderFromRequest($request, $component); return Helper::getRedirectOption($request, $component->id, 'Components') ->with('success', trans('admin/components/message.create.success')); } return redirect()->back()->withInput()->withErrors($component->getErrors()); } /** * Return a view to edit a component. * * @author [A. Gianotto] [] * * @see ComponentsController::postEdit() method that stores the data. * @since [v3.0] * * @param int $componentId * @return View * * @throws AuthorizationException */ public function edit(Component $component) { $this->authorize('update', $component); if ($safeReferer = Helper::sameOriginUrl(url()->previous())) { session()->put('url.intended', $safeReferer); } return view('components/edit') ->with('item', $component) ->with('category_type', 'component'); } /** * Return a view to edit a component. * * @author [A. Gianotto] [] * * @see ComponentsController::getEdit() method presents the form. * * @param int $componentId * @return RedirectResponse * * @throws AuthorizationException * * @since [v3.0] */ public function update(UpdateComponentRequest $request, Component $component) { $this->authorize('update', $component); // qty and order_number are intentionally NOT accepted on update. // See AccessoriesController::update for rationale. supplier_id is // editable again (imperfect single-value semantics accepted for // the info-panel display). $component->name = $request->input('name'); $component->category_id = $request->input('category_id'); $component->manufacturer_id = $request->input('manufacturer_id'); $component->model_number = $request->input('model_number'); $component->location_id = $request->input('location_id'); $component->company_id = Company::getIdForCurrentUser($request->input('company_id')); $component->min_amt = $request->input('min_amt'); $component->serial = $request->input('serial'); // supplier_id, purchase_date, purchase_cost are create-only on // the parent. Post-create acquisitions live as Orders + // OrderItems. default_supplier_id remains editable as the // parent's "typical supplier" template. $component->default_supplier_id = $request->input('default_supplier_id'); $component->notes = $request->input('notes'); $component = $request->handleImages($component); session()->put(['redirect_option' => $request->input('redirect_option')]); if ($component->save()) { return Helper::getRedirectOption($request, $component->id, 'Components') ->with('success', trans('admin/components/message.update.success')); } return redirect()->back()->withInput()->withErrors($component->getErrors()); } /** * Delete a component. * * @author [A. Gianotto] [] * * @since [v3.0] * * @param int $componentId * @return RedirectResponse * * @throws AuthorizationException */ public function destroy($componentId) { if (is_null($component = Component::find($componentId))) { return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist')); } $this->authorize('delete', $component); // Note: the image file is deliberately preserved across this // soft-delete. Snipe-IT's `snipeit:purge` command permanently // removes it later when the row is force-deleted. Keeping the // file here means a restored soft-deleted row still has its // image. if ($component->numCheckedOut() > 0) { return redirect()->route('components.index')->with('error', trans('admin/components/message.delete.error_qty')); } $component->delete(); return redirect()->route('components.index')->with('success', trans('admin/components/message.delete.success')); } /** * Return a view to display component information. * * @author [A. Gianotto] [] * * @see ComponentsController::getDataView() method that generates the JSON response * @since [v3.0] * * @param int $componentId * @return View * * @throws AuthorizationException */ public function show(Component $component) { $this->authorize('view', $component); return view('components/view', compact('component'))->with('snipe_component', $component); } public function getClone(Component $component): View|RedirectResponse { $this->authorize('create', Component::class); $cloned_component = clone $component; $cloned_component->id = null; $cloned_component->deleted_at = null; // Show the page return view('components/edit') ->with('item', $cloned_component) ->with('component', $cloned_component); } /** * Apply an on-hand quantity delta (+/-) and log the change. The * shared body lives on the HandlesAdjustQuantity trait; this method * only owns the redirect-response shape. */ public function adjustQuantity(AdjustQuantityRequest $request, Component $component): RedirectResponse { $error = $this->runAdjustQuantity($request, $component, 'components'); if ($error) { return redirect()->back()->with('error', $error); } return redirect() ->route('components.show', $component) ->withFragment('history') ->with('success', trans('general.adjust_quantity_success')); } }