productRepository->filter( [ 'page' => $request->get('page') ?? 1 ] ); $title = "List All Product"; return view('administrator.pages.product.index', compact('title', 'products')); } public function create(Request $request) { $step = $request->get('step') ?? 1; $title = 'Add new product'; // Fetch Product Categories (Roots only, children via relation) $group = \App\Models\ProductCategories::where('is_active', \App\Enums\Status::ACTIVE->value)->whereNull('parent_id')->get(); $type = null; // Fetch OS versions with their group for the OS selector component $osVersions = \App\Models\Os::with('osGroup')->where('status', 1)->get(); // Fetch Control Panels for Hosting products $controlPanels = \App\Models\ControlPanel::active()->ordered()->get(); if ($step === 1) { return view("administrator.pages.product.create", compact('group', 'type', 'title', 'osVersions', 'controlPanels')); } if (!$request->has(['step', 'type'])) { return back()->withErrors('Missing step or type'); } $type_id = (int) $request->type; $product_name = $request->name; $view = "administrator.pages.product.create"; $data = compact('type_id', 'title', 'group', 'type', 'product_name', 'osOptions'); return view($view, $data); } public function store(ProductRequest $request) { try { $this->productService->store($request->validated()); return redirect()->route('products.index')->with('success', 'Add new product success'); } catch (Exception $e) { return back()->withErrors($e->getMessage())->withInput(); } } public function edit(Request $request, $id) { $product = $this->productRepository->find($id); if (!$product) { return back()->withErrors("Can't find product."); } // Load relationships $product->load(['pricings', 'osVersions', 'category']); $title = 'Edit product: ' . $product->name; $group = \App\Models\ProductCategories::where('is_active', \App\Enums\Status::ACTIVE->value)->whereNull('parent_id')->get(); $type = null; // Fetch OS versions for select $osVersions = \App\Models\Os::with('osGroup')->where('status', 1)->get(); $view = "administrator.pages.product.edit"; // Fetch Control Panels for Hosting products $controlPanels = \App\Models\ControlPanel::active()->ordered()->get(); $data = compact('product', 'title', 'group', 'type', 'osVersions', 'controlPanels'); return view($view, $data); } public function update(ProductRequest $request, $id) { try { $this->productService->update((int) $id, $request->validated()); return redirect()->route('products.index')->with('success', 'Update product success'); } catch (Exception $e) { return back()->withErrors($e->getMessage())->withInput(); } } public function destroy(Request $request, $id) { try { $this->productService->delete((int) $id); return redirect()->route('products.index')->with('success', 'Deleted successfully'); } catch (Exception $e) { return back()->withErrors($e->getMessage()); } } public function duplicate($id) { try { $product = $this->productRepository->find($id); if (!$product) { return back()->withErrors("Can't find product."); } $product->load(['pricings', 'osVersions', 'controlPanels']); $newData = $product->only([ 'short_description', 'description', 'setup_fee', 'trial_days', 'cpu', 'ram', 'gpu', 'disk', 'bandwidth', 'stock', 'is_unlimited', 'is_active', 'sort_order', 'product_type', 'product_categories_id', 'published_at', ]); $newData['name'] = $product->name . ' (Copy)'; $newProduct = $this->productService->store($newData); if ($product->osVersions->isNotEmpty()) { $newProduct->osVersions()->sync($product->osVersions->pluck('id')); } if ($product->controlPanels->isNotEmpty()) { $syncData = []; foreach ($product->controlPanels as $panel) { $syncData[$panel->id] = [ 'price_modifier' => $panel->pivot->price_modifier, 'is_default' => $panel->pivot->is_default, ]; } $newProduct->controlPanels()->sync($syncData); } if ($product->pricings->isNotEmpty()) { foreach ($product->pricings as $pricing) { $newProduct->pricings()->create([ 'billing_cycle' => $pricing->billing_cycle, 'price' => $pricing->price, 'price_sale' => $pricing->price_sale, 'currency' => $pricing->currency, 'is_active' => $pricing->is_active, ]); } } return redirect()->route('products.edit', ['id' => $newProduct->id]) ->with('success', 'Product duplicated successfully'); } catch (Exception $e) { return back()->withErrors($e->getMessage()); } } public function datatable(Request $request) { $query = $this->productRepository->filter( $request->all(), ['category', 'pricings'], [], ['*'], true ); return DataTables::eloquent($query) ->addColumn('category', function ($d) { return view('administrator.pages.product.datatable.category', ['row' => $d])->render(); }) ->addColumn('price', function ($d) { return view('administrator.pages.product.datatable.price', ['row' => $d])->render(); }) ->addColumn('specs', function ($d) { return view('administrator.pages.product.datatable.specs', ['row' => $d])->render(); }) ->addColumn('status', function ($d) { return view('administrator.pages.product.datatable.status', ['row' => $d])->render(); }) ->addColumn('action', function ($d) { return view('administrator.pages.product.datatable.action', ['row' => $d])->render(); }) ->rawColumns(['category', 'price', 'specs', 'status', 'action']) ->make(true); } private function mapEnumToTypeId(?ProductTypeEnums $enum): int { return match ($enum) { ProductTypeEnums::ADDON => 1, ProductTypeEnums::DOMAIN => 2, ProductTypeEnums::HOSTING => 3, ProductTypeEnums::VPS => 4, default => 0 }; } public function export(Request $request) { if ($request->get('sample') == 1) { return Excel::download(new ProductsExport(), 'products_sample.xlsx'); } return Excel::download(new ProductsExport(), 'products_' . date('Y-m-d') . '.xlsx'); } public function import(Request $request) { $request->validate([ 'file' => 'required|mimes:xlsx,xls,csv' ]); try { Excel::import(new ProductsImport(), $request->file('file')); return redirect()->route('products.index')->with('success', 'Import products successfully'); } catch (\Maatwebsite\Excel\Validators\ValidationException $e) { $failures = $e->failures(); $errorMessage = 'Import failed at row(s): '; foreach ($failures as $failure) { $errorMessage .= $failure->row() . ' (' . implode(', ', $failure->errors()) . '); '; } return back()->withErrors($errorMessage); } catch (\Exception $e) { return back()->withErrors('Import failed: ' . $e->getMessage()); } } }