Files

257 lines
9.0 KiB
PHP

<?php
namespace App\Http\Controllers\admin\product;
use App\Exports\ProductsExport;
use App\Imports\ProductsImport;
use App\Enums\Product\ProductTypeEnums;
use App\Http\Controllers\Controller;
use App\Http\Requests\Product\ProductRequest;
use App\Http\Services\ProductService;
use App\Repositories\Group\GroupRepositoryInterface;
use App\Repositories\Admin\Product\ProductRepositoryInterface;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
use Yajra\DataTables\Facades\DataTables;
use Exception;
class ProductController extends Controller
{
public function __construct(
public GroupRepositoryInterface $groupRepository,
public ProductRepositoryInterface $productRepository,
public ProductService $productService
) {
parent::__construct();
}
public function index(Request $request)
{
$products = $this->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());
}
}
}