diff --git a/src/app/Http/Controllers/EcommerceController.php b/src/app/Http/Controllers/EcommerceController.php new file mode 100644 index 0000000..26b8de9 --- /dev/null +++ b/src/app/Http/Controllers/EcommerceController.php @@ -0,0 +1,179 @@ +baseUrl($baseUrl . '/wp-json/wc/v3/'); + } + + /** + * Get start and end dates from the request. + */ + private function dateRange(Request $request): array + { + $from = $request->query('from'); + $to = $request->query('to'); + + if (!$from && !$to) { + return [null, null]; + } + + return [ + $from ? $from . 'T00:00:00' : null, + $to ? $to . 'T23:59:59' : null, + ]; + } + + /** + * Summary metrics (Net Sales, Total Orders, Total Customers). + */ + public function summary(Request $request) + { + $client = $this->wooClient(); + if (!$client) { + return response()->json(['error' => 'API credentials missing.'], 500); + } + + [$from, $to] = $this->dateRange($request); + + $params = []; + if ($from) $params['date_min'] = $from; + if ($to) $params['date_max'] = $to; + + try { + // Get Sales Report + $salesResp = $client->get('reports/sales', $params); + $salesData = $salesResp->successful() ? $salesResp->json() : []; + $totals = !empty($salesData) ? $salesData[0] : [ + 'total_sales' => 0, + 'net_sales' => 0, + 'total_orders' => 0 + ]; + + // For total customers, we count users with role customer. + $custParams = ['role' => 'customer', 'per_page' => 1]; + $custResp = $client->get('customers', $custParams); + $totalCustomers = 0; + if ($custResp->successful() && $custResp->header('X-WP-Total')) { + $totalCustomers = (int) $custResp->header('X-WP-Total'); + } + + return response()->json([ + 'net_sales' => (float) ($totals['net_sales'] ?? 0), + 'total_sales' => (float) ($totals['total_sales'] ?? 0), + 'total_orders' => (int) ($totals['total_orders'] ?? 0), + 'total_customers' => $totalCustomers, + 'avg_order_value' => ($totals['total_orders'] ?? 0) > 0 ? ((float) ($totals['net_sales'] ?? 0)) / (int) $totals['total_orders'] : 0, + ]); + + } catch (\Exception $e) { + Log::error('WooCommerce API Error (summary): ' . $e->getMessage()); + return response()->json(['error' => 'Failed to fetch WooCommerce data.'], 500); + } + } + + /** + * Recent Orders list. + */ + public function recentOrders(Request $request) + { + $client = $this->wooClient(); + if (!$client) { + return response()->json(['error' => 'API credentials missing.'], 500); + } + + [$from, $to] = $this->dateRange($request); + + $params = [ + 'per_page' => 10, + 'orderby' => 'date', + 'order' => 'desc', + ]; + + if ($from) $params['after'] = $from; + if ($to) $params['before'] = $to; + + try { + $resp = $client->get('orders', $params); + $data = $resp->successful() ? $resp->json() : []; + + $orders = array_map(function($order) { + return [ + 'id' => $order['id'], + 'number' => $order['number'], + 'status' => $order['status'], + 'total' => (float) $order['total'], + 'currency' => $order['currency'], + 'date_created' => $order['date_created'], + 'customer' => $order['billing']['first_name'] . ' ' . $order['billing']['last_name'], + ]; + }, $data); + + return response()->json($orders); + } catch (\Exception $e) { + Log::error('WooCommerce API Error (orders): ' . $e->getMessage()); + return response()->json(['error' => 'Failed to fetch WooCommerce data.'], 500); + } + } + + /** + * Top Selling Products list. + */ + public function topProducts(Request $request) + { + $client = $this->wooClient(); + if (!$client) { + return response()->json(['error' => 'API credentials missing.'], 500); + } + + [$from, $to] = $this->dateRange($request); + + $params = [ + 'per_page' => 10, + ]; + + if ($from) $params['date_min'] = $from; + if ($to) $params['date_max'] = $to; + + try { + $resp = $client->get('reports/top_sellers', $params); + $data = $resp->successful() ? $resp->json() : []; + + return response()->json($data); + } catch (\Exception $e) { + Log::error('WooCommerce API Error (top_sellers): ' . $e->getMessage()); + return response()->json(['error' => 'Failed to fetch WooCommerce data.'], 500); + } + } +} diff --git a/src/resources/views/ecommerce.blade.php b/src/resources/views/ecommerce.blade.php new file mode 100644 index 0000000..9342fea --- /dev/null +++ b/src/resources/views/ecommerce.blade.php @@ -0,0 +1,369 @@ + + + + + + E-Commerce Dashboard - Stargas + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + + + + +
+ + +
+
+
+ Stargas Energies +
+

E-Commerce Dashboard

+

WooCommerce Analytics

+
+
+
+ + + Hub + + + +
+
+ + +
+ + + + + +
+ + + + + + + + +
+
+ +
+ + + + +
+
+
+ Net Sales +
+ +
+
+
+
R 0.00
+
+
+ +
+
+ Total Orders +
+ +
+
+
+
0
+
+
+ +
+
+ Avg Order Value +
+ +
+
+
+
R 0.00
+
+
+ +
+
+ Total Customers +
+ +
+
+
+
0
+
+
+
+ + +
+ + +
+
+

+ + Recent Orders +

+
+
+ + + + + + + + + + + + + +
Order #CustomerDateStatusTotal
+
+
+ + +
+
+

+ + Top Selling Products +

+
+
+ + + + + + + + + + +
ProductQty Sold
+
+
+ +
+
+ + + + + diff --git a/src/resources/views/landing.blade.php b/src/resources/views/landing.blade.php index bd2adba..a98d5d2 100644 --- a/src/resources/views/landing.blade.php +++ b/src/resources/views/landing.blade.php @@ -78,12 +78,8 @@ Stargas Energies -

- Systems Hub -

-

- Select a module below to access real-time analytics and powerful management tools for your division. -

+ + @@ -110,10 +106,10 @@ - +
- Planned + Active
diff --git a/src/routes/web.php b/src/routes/web.php index e49fdfd..9b37bac 100644 --- a/src/routes/web.php +++ b/src/routes/web.php @@ -2,6 +2,7 @@ use App\Http\Controllers\DashboardController; use App\Http\Controllers\AdminController; +use App\Http\Controllers\EcommerceController; use Illuminate\Support\Facades\Route; Route::get('/', function() { @@ -9,6 +10,7 @@ }); Route::get('/procurement', [DashboardController::class, 'index']); +Route::get('/ecommerce', [EcommerceController::class, 'index']); // Admin endpoints Route::prefix('admin')->group(function () { @@ -28,3 +30,10 @@ Route::get('/supplier/{code}', [DashboardController::class, 'supplierProducts']); Route::get('/product-details', [DashboardController::class, 'productDetails']); }); + +// E-Commerce API endpoints +Route::prefix('api/ecommerce')->group(function () { + Route::get('/summary', [EcommerceController::class, 'summary']); + Route::get('/recent-orders', [EcommerceController::class, 'recentOrders']); + Route::get('/top-products', [EcommerceController::class, 'topProducts']); +});