diff --git a/app/Exports/ProductCategoriesExport.php b/app/Exports/ProductCategoriesExport.php
new file mode 100644
index 0000000..88bdf48
--- /dev/null
+++ b/app/Exports/ProductCategoriesExport.php
@@ -0,0 +1,44 @@
+get();
+ }
+
+ public function headings(): array
+ {
+ return [
+ 'ID',
+ 'Name',
+ 'Slug',
+ 'Parent Name',
+ 'Parent ID',
+ 'Type',
+ 'Is Active',
+ 'Sort Order',
+ ];
+ }
+
+ public function map($category): array
+ {
+ return [
+ $category->id,
+ $category->name,
+ $category->slug,
+ $category->parent?->name,
+ $category->parent_id,
+ $category->type,
+ $category->is_active ? 'Yes' : 'No',
+ $category->sort_order,
+ ];
+ }
+}
diff --git a/app/Exports/ProductsExport.php b/app/Exports/ProductsExport.php
new file mode 100644
index 0000000..418d654
--- /dev/null
+++ b/app/Exports/ProductsExport.php
@@ -0,0 +1,72 @@
+get();
+ }
+
+ public function headings(): array
+ {
+ return [
+ 'ID',
+ 'Name',
+ 'Slug',
+ 'Category',
+ 'Category ID',
+ 'Short Description',
+ 'Description',
+ 'Setup Fee',
+ 'Trial Days',
+ 'CPU',
+ 'RAM',
+ 'GPU',
+ 'Disk',
+ 'Bandwidth',
+ 'Stock',
+ 'Is Unlimited',
+ 'Is Active',
+ 'Sort Order',
+ 'Product Type',
+ 'Published At',
+ 'Monthly Price',
+ 'Sale Price',
+ ];
+ }
+
+ public function map($product): array
+ {
+ return [
+ $product->id,
+ $product->name,
+ $product->slug,
+ $product->category?->name,
+ $product->product_categories_id,
+ $product->short_description,
+ $product->description,
+ $product->setup_fee,
+ $product->trial_days,
+ $product->cpu,
+ $product->ram,
+ $product->gpu,
+ $product->disk,
+ $product->bandwidth,
+ $product->stock,
+ $product->is_unlimited ? 'Yes' : 'No',
+ $product->is_active ? 'Yes' : 'No',
+ $product->sort_order,
+ $product->product_type,
+ $product->published_at?->format('Y-m-d'),
+ $product->pricings->where('billing_cycle', 'monthly')->where('is_active', 1)->first()?->price ?? '',
+ $product->pricings->where('billing_cycle', 'monthly')->where('is_active', 1)->first()?->price_sale ?? '',
+ ];
+ }
+}
diff --git a/app/Http/Controllers/admin/product/ProductCategoryController.php b/app/Http/Controllers/admin/product/ProductCategoryController.php
index b0bf0aa..2d0cab9 100644
--- a/app/Http/Controllers/admin/product/ProductCategoryController.php
+++ b/app/Http/Controllers/admin/product/ProductCategoryController.php
@@ -6,7 +6,10 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\ProductCategories\ProductCategoryRequest;
use App\Http\Services\Admin\ProductCategory\ProductCategoryServiceInterface;
use App\Repositories\Admin\ProductCategory\ProductCategoryRepositoryInterface;
+use App\Exports\ProductCategoriesExport;
+use App\Imports\ProductCategoriesImport;
use Illuminate\Http\Request;
+use Maatwebsite\Excel\Facades\Excel;
use Yajra\DataTables\Facades\DataTables;
@@ -139,4 +142,33 @@ class ProductCategoryController extends Controller
->rawColumns(['details_control', 'action', 'is_active', 'checkbox', 'sub_group_html'])
->make(true);
}
+
+ public function export(Request $request)
+ {
+ if ($request->get('sample') == 1) {
+ return Excel::download(new ProductCategoriesExport(), 'product_categories_sample.xlsx');
+ }
+ return Excel::download(new ProductCategoriesExport(), 'product_categories_' . date('Y-m-d') . '.xlsx');
+ }
+
+ public function import(Request $request)
+ {
+ $request->validate([
+ 'file' => 'required|mimes:xlsx,xls,csv'
+ ]);
+
+ try {
+ Excel::import(new ProductCategoriesImport(), $request->file('file'));
+ return redirect()->route('products.group.index')->with('success', 'Import product categories 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());
+ }
+ }
}
\ No newline at end of file
diff --git a/app/Http/Controllers/admin/product/ProductController.php b/app/Http/Controllers/admin/product/ProductController.php
index 67c9c92..93a361f 100644
--- a/app/Http/Controllers/admin/product/ProductController.php
+++ b/app/Http/Controllers/admin/product/ProductController.php
@@ -2,14 +2,16 @@
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;
@@ -222,4 +224,33 @@ class ProductController extends Controller
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());
+ }
+ }
}
diff --git a/app/Imports/ProductCategoriesImport.php b/app/Imports/ProductCategoriesImport.php
new file mode 100644
index 0000000..e4bc366
--- /dev/null
+++ b/app/Imports/ProductCategoriesImport.php
@@ -0,0 +1,46 @@
+first();
+ $parentId = $parent?->id;
+ }
+
+ if (!empty($row['parent_id'])) {
+ $parentId = (int) $row['parent_id'];
+ }
+
+ return new ProductCategories([
+ 'name' => $row['name'],
+ 'slug' => $row['slug'] ?? Str::slug($row['name']),
+ 'parent_id' => $parentId,
+ 'type' => $row['type'] ?? null,
+ 'is_active' => in_array(strtolower($row['is_active'] ?? ''), ['yes', '1', 'true']),
+ 'sort_order' => $row['sort_order'] ?? 0,
+ ]);
+ }
+
+ public function rules(): array
+ {
+ return [
+ 'name' => 'required|string|max:255',
+ 'slug' => 'nullable|string|max:255',
+ 'parent_name' => 'nullable|string|max:255',
+ 'parent_id' => 'nullable|integer|exists:product_categories,id',
+ 'type' => 'nullable|string|max:50',
+ ];
+ }
+}
diff --git a/app/Imports/ProductsImport.php b/app/Imports/ProductsImport.php
new file mode 100644
index 0000000..002778c
--- /dev/null
+++ b/app/Imports/ProductsImport.php
@@ -0,0 +1,59 @@
+first();
+ $categoryId = $category?->id;
+ }
+
+ if (!empty($row['category_id'])) {
+ $categoryId = (int) $row['category_id'];
+ }
+
+ return new Product([
+ 'uuid' => (string) Str::uuid(),
+ 'name' => $row['name'],
+ 'slug' => $row['slug'] ?? Str::slug($row['name']),
+ 'product_categories_id' => $categoryId,
+ 'short_description' => $row['short_description'] ?? null,
+ 'description' => $row['description'] ?? null,
+ 'setup_fee' => $row['setup_fee'] ?? 0,
+ 'trial_days' => $row['trial_days'] ?? 0,
+ 'cpu' => $row['cpu'] ?? null,
+ 'ram' => $row['ram'] ?? null,
+ 'gpu' => $row['gpu'] ?? null,
+ 'disk' => $row['disk'] ?? null,
+ 'bandwidth' => $row['bandwidth'] ?? null,
+ 'stock' => $row['stock'] ?? 0,
+ 'is_unlimited' => in_array(strtolower($row['is_unlimited'] ?? ''), ['yes', '1', 'true']),
+ 'is_active' => in_array(strtolower($row['is_active'] ?? ''), ['yes', '1', 'true']),
+ 'sort_order' => $row['sort_order'] ?? 0,
+ 'published_at' => !empty($row['published_at']) ? \Carbon\Carbon::parse($row['published_at']) : null,
+ ]);
+ }
+
+ public function rules(): array
+ {
+ return [
+ 'name' => 'required|string|max:255',
+ 'slug' => 'nullable|string|max:255',
+ 'category' => 'nullable|string|max:255',
+ 'category_id' => 'nullable|integer|exists:product_categories,id',
+ ];
+ }
+}
diff --git a/resources/views/administrator/pages/block/product/btn.blade.php b/resources/views/administrator/pages/block/product/btn.blade.php
index fa02499..997499c 100644
--- a/resources/views/administrator/pages/block/product/btn.blade.php
+++ b/resources/views/administrator/pages/block/product/btn.blade.php
@@ -7,6 +7,36 @@