Skip to main content
Glama
GetOrderAnalyticsTool.php10.5 kB
<?php namespace App\MCP\Tools; use App\Models\Order; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; use OPGG\LaravelMcpServer\Enums\ProcessMessageType; use OPGG\LaravelMcpServer\Exceptions\Enums\JsonRpcErrorCode; use OPGG\LaravelMcpServer\Exceptions\JsonRpcErrorException; use OPGG\LaravelMcpServer\Services\ToolService\ToolInterface; class GetOrderAnalyticsTool implements ToolInterface { public function messageType(): ProcessMessageType { return ProcessMessageType::HTTP; } public function name(): string { return 'get_order_analytics'; } public function description(): string { return '獲取訂單分析資料,包括按日期、狀態、產品的統計分析'; } public function inputSchema(): array { return [ 'type' => 'object', 'properties' => [ 'analytics_type' => [ 'type' => 'string', 'enum' => ['daily', 'status', 'product', 'monthly'], 'description' => '分析類型:daily(按日統計)、status(按狀態統計)、product(按產品統計)、monthly(按月統計)- Optional field (default: daily)', 'default' => 'daily', ], 'date_from' => [ 'type' => 'string', 'format' => 'date', 'description' => '分析開始日期 (YYYY-MM-DD) - Optional field', ], 'date_to' => [ 'type' => 'string', 'format' => 'date', 'description' => '分析結束日期 (YYYY-MM-DD) - Optional field', ], 'status' => [ 'type' => 'string', 'description' => '篩選特定訂單狀態(pending, completed, cancelled, all)- Optional field. Use "all" to include all statuses', ], 'limit' => [ 'type' => 'integer', 'description' => '返回結果數量限制 - Optional field (default: 30, range: 1-100)', 'default' => 30, 'minimum' => 1, 'maximum' => 100, ], ], ]; } public function annotations(): array { return []; } public function execute(array $arguments): array { $validator = Validator::make($arguments, [ 'analytics_type' => ['nullable', 'string', 'in:daily,status,product,monthly'], 'date_from' => ['nullable', 'date'], 'date_to' => ['nullable', 'date', 'after_or_equal:date_from'], 'status' => ['nullable', 'string', 'in:pending,completed,cancelled,all'], 'limit' => ['nullable', 'integer', 'min:1', 'max:100'], ]); if ($validator->fails()) { throw new JsonRpcErrorException( message: $validator->errors()->toJson(), code: JsonRpcErrorCode::INVALID_REQUEST ); } try { $analyticsType = $arguments['analytics_type'] ?? 'daily'; $limit = $arguments['limit'] ?? 30; \Log::info('GetOrderAnalyticsTool arguments:', $arguments); \Log::info('GetOrderAnalyticsTool status value type: ' . gettype($arguments['status'] ?? 'not set')); \Log::info('GetOrderAnalyticsTool status value: ', ['status' => $arguments['status'] ?? 'not set']); $baseQuery = Order::query(); // Apply date filters if (!empty($arguments['date_from'])) { $baseQuery->whereDate('created_at', '>=', $arguments['date_from']); \Log::info('Applied date_from filter: ' . $arguments['date_from']); } if (!empty($arguments['date_to'])) { $baseQuery->whereDate('created_at', '<=', $arguments['date_to']); \Log::info('Applied date_to filter: ' . $arguments['date_to']); } if (isset($arguments['status']) && $arguments['status'] !== '' && $arguments['status'] !== null) { if ($arguments['status'] === 'all') { // Don't apply any status filter when "all" is specified \Log::info('Status filter set to "all" - no status filtering applied'); } else { $baseQuery->where('status', $arguments['status']); \Log::info('Applied status filter: ' . $arguments['status']); } } elseif (isset($arguments['status']) && $arguments['status'] === '') { // Default to 'completed' when status is empty string $baseQuery->where('status', 'completed'); \Log::info('Applied default status filter: completed (because status was empty string)'); } else { \Log::info('Status filter not applied. Status value: ' . json_encode($arguments['status'] ?? 'not set')); } \Log::info('Base query before analytics - SQL: ' . $baseQuery->toSql()); \Log::info('Base query before analytics - Bindings: ', $baseQuery->getBindings()); $analytics = []; switch ($analyticsType) { case 'daily': $analytics = $this->getDailyAnalytics($baseQuery, $limit); break; case 'monthly': $analytics = $this->getMonthlyAnalytics($baseQuery, $limit); break; case 'status': $analytics = $this->getStatusAnalytics($baseQuery); break; case 'product': $analytics = $this->getProductAnalytics($baseQuery, $limit); break; } return [ 'success' => true, 'analytics_type' => $analyticsType, 'data' => $analytics, ]; } catch (\Exception $e) { throw new JsonRpcErrorException( message: "Failed to retrieve order analytics: " . $e->getMessage(), code: JsonRpcErrorCode::INTERNAL_ERROR ); } } private function getDailyAnalytics($query, $limit): array { return $query->select([ DB::raw('DATE(created_at) as date'), DB::raw('COUNT(*) as order_count'), DB::raw('SUM(amount) as total_revenue'), DB::raw('AVG(amount) as average_order_value'), DB::raw('COUNT(DISTINCT name) as unique_customers') ]) ->groupBy(DB::raw('DATE(created_at)')) ->orderBy('date', 'desc') ->limit($limit) ->get() ->map(function ($item) { return [ 'date' => $item->date, 'order_count' => $item->order_count, 'total_revenue' => round($item->total_revenue, 2), 'average_order_value' => round($item->average_order_value, 2), 'unique_customers' => $item->unique_customers, ]; }) ->toArray(); } private function getMonthlyAnalytics($query, $limit): array { return $query->select([ DB::raw('YEAR(created_at) as year'), DB::raw('MONTH(created_at) as month'), DB::raw('COUNT(*) as order_count'), DB::raw('SUM(amount) as total_revenue'), DB::raw('AVG(amount) as average_order_value'), DB::raw('COUNT(DISTINCT name) as unique_customers') ]) ->groupBy(DB::raw('YEAR(created_at)'), DB::raw('MONTH(created_at)')) ->orderBy('year', 'desc') ->orderBy('month', 'desc') ->limit($limit) ->get() ->map(function ($item) { return [ 'year' => $item->year, 'month' => $item->month, 'month_name' => date('F', mktime(0, 0, 0, $item->month, 1)), 'order_count' => $item->order_count, 'total_revenue' => round($item->total_revenue, 2), 'average_order_value' => round($item->average_order_value, 2), 'unique_customers' => $item->unique_customers, ]; }) ->toArray(); } private function getStatusAnalytics($query): array { return $query->select([ 'status', DB::raw('COUNT(*) as order_count'), DB::raw('SUM(amount) as total_revenue'), DB::raw('AVG(amount) as average_order_value'), DB::raw('COUNT(DISTINCT name) as unique_customers') ]) ->groupBy('status') ->orderBy('order_count', 'desc') ->get() ->map(function ($item) { return [ 'status' => $item->status, 'order_count' => $item->order_count, 'total_revenue' => round($item->total_revenue, 2), 'average_order_value' => round($item->average_order_value, 2), 'unique_customers' => $item->unique_customers, ]; }) ->toArray(); } private function getProductAnalytics($query, $limit): array { // Add debug logging to confirm status filter is applied \Log::info('GetProductAnalytics - Query SQL: ' . $query->toSql()); \Log::info('GetProductAnalytics - Query bindings: ', $query->getBindings()); return $query->with('product') ->select([ 'product_id', DB::raw('COUNT(*) as order_count'), DB::raw('SUM(quantity) as total_quantity'), DB::raw('SUM(amount) as total_revenue'), DB::raw('AVG(amount) as average_order_value') ]) ->groupBy('product_id') ->orderBy('total_quantity', 'desc') // Changed from total_revenue to total_quantity for "most sold products" ->limit($limit) ->get() ->map(function ($item) { return [ 'product_id' => $item->product_id, 'product_name' => $item->product->name ?? 'Unknown', 'order_count' => $item->order_count, 'total_quantity' => $item->total_quantity, 'total_revenue' => round($item->total_revenue, 2), 'average_order_value' => round($item->average_order_value, 2), ]; }) ->toArray(); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/uberr2000/mcp_demo'

If you have feedback or need assistance with the MCP directory API, please join our Discord server