Skip to main content
Glama
GetOrderAnalyticsTool.js9.37 kB
import { BaseTool } from "./BaseTool.js"; import Joi from "joi"; import db from "../database.js"; export class GetOrderAnalyticsTool extends BaseTool { get name() { return "get_order_analytics"; } get description() { return "獲取訂單分析數據,包括每日訂單量、月度訂單量、訂單狀態分布、產品銷售分析等"; } get inputSchema() { return { type: "object", properties: { analytics_type: { type: "string", enum: ["daily", "monthly", "status", "product"], description: "分析類型:daily(每日)、monthly(月度)、status(狀態)、product(產品) - Required field", }, date_from: { type: "string", format: "date", description: "開始日期 (YYYY-MM-DD format) - Optional field", }, date_to: { type: "string", format: "date", description: "結束日期 (YYYY-MM-DD format) - Optional field", }, status: { type: "string", enum: [ "pending", "processing", "completed", "cancelled", "refunded", "all", ], description: "訂單狀態篩選 - Optional field", }, limit: { type: "integer", description: "返回結果數量限制 - Optional field (default: 30, max: 100)", default: 30, minimum: 1, maximum: 100, }, }, required: ["analytics_type"], }; } validateInput(input) { const schema = Joi.object({ analytics_type: Joi.string() .valid("daily", "monthly", "status", "product") .required(), date_from: Joi.date().allow("", null), date_to: Joi.date().min(Joi.ref("date_from")).allow("", null), status: Joi.string() .valid( "pending", "processing", "completed", "cancelled", "refunded", "all" ) .allow("", null), limit: Joi.number().integer().min(1).max(100).default(30), }); const { error } = schema.validate(input); if (error) { throw new Error(`Validation error: ${error.message}`); } return true; } async execute(params) { try { this.validateInput(params); // 构建基础查询条件 const whereConditions = []; const queryParams = []; if (params.status && params.status !== "all") { whereConditions.push("status = ?"); queryParams.push(params.status); } if (params.date_from) { whereConditions.push("created_at >= ?"); queryParams.push(params.date_from); } if (params.date_to) { whereConditions.push("created_at <= ?"); queryParams.push(params.date_to); } const whereClause = whereConditions.length > 0 ? "WHERE " + whereConditions.join(" AND ") : ""; const limit = params.limit || 30; let analytics; switch (params.analytics_type) { case "daily": analytics = await this.getDailyAnalytics(whereClause, queryParams, limit); break; case "monthly": analytics = await this.getMonthlyAnalytics(whereClause, queryParams, limit); break; case "status": analytics = await this.getStatusAnalytics(whereClause, queryParams); break; case "product": analytics = await this.getProductAnalytics(whereClause, queryParams, limit); break; default: throw new Error("Invalid analytics type"); } return { success: true, analytics_type: params.analytics_type, data: analytics, }; } catch (error) { throw new Error( `Failed to retrieve order analytics: ${error.message}` ); } } async getDailyAnalytics(whereClause, queryParams, limit) { try { const sql = ` SELECT DATE(created_at) as date, COUNT(*) as order_count, SUM(amount) as total_amount, AVG(amount) as avg_amount FROM orders ${whereClause} GROUP BY DATE(created_at) ORDER BY date DESC LIMIT ? `; const results = await db.query(sql, [...queryParams, limit]); return results.map(row => ({ date: row.date, order_count: row.order_count, total_amount: parseFloat(row.total_amount) || 0, avg_amount: parseFloat(row.avg_amount) || 0 })); } catch (error) { console.error('Error in getDailyAnalytics:', error); throw error; } } async getMonthlyAnalytics(whereClause, queryParams, limit) { try { const sql = ` SELECT DATE_FORMAT(created_at, '%Y-%m') as month, COUNT(*) as order_count, SUM(amount) as total_amount, AVG(amount) as avg_amount FROM orders ${whereClause} GROUP BY DATE_FORMAT(created_at, '%Y-%m') ORDER BY month DESC LIMIT ? `; const results = await db.query(sql, [...queryParams, limit]); return results.map(row => ({ month: row.month, order_count: row.order_count, total_amount: parseFloat(row.total_amount) || 0, avg_amount: parseFloat(row.avg_amount) || 0 })); } catch (error) { console.error('Error in getMonthlyAnalytics:', error); throw error; } } async getStatusAnalytics(whereClause, queryParams) { try { const sql = ` SELECT status, COUNT(*) as count, SUM(amount) as total_amount, AVG(amount) as avg_amount FROM orders ${whereClause} GROUP BY status ORDER BY count DESC `; const results = await db.query(sql, queryParams); return results.map(row => ({ status: row.status, count: row.count, total_amount: parseFloat(row.total_amount) || 0, avg_amount: parseFloat(row.avg_amount) || 0 })); } catch (error) { console.error('Error in getStatusAnalytics:', error); throw error; } } async getProductAnalytics(whereClause, queryParams, limit) { try { // 修改 WHERE 子句以使用表别名 let modifiedWhereClause = whereClause.replace(/created_at/g, 'o.created_at'); modifiedWhereClause = modifiedWhereClause.replace(/status/g, 'o.status'); // Join orders with products to get product analytics const sql = ` SELECT p.name as product_name, p.id as product_id, COUNT(o.id) as order_count, SUM(o.quantity) as total_quantity, SUM(o.amount) as total_amount, AVG(o.amount) as avg_order_amount FROM orders o INNER JOIN products p ON o.product_id = p.id ${modifiedWhereClause} GROUP BY p.id, p.name ORDER BY total_amount DESC LIMIT ? `; const results = await db.query(sql, [...queryParams, limit]); return results.map(row => ({ product_id: row.product_id, product_name: row.product_name, order_count: row.order_count, total_quantity: row.total_quantity, total_amount: parseFloat(row.total_amount) || 0, avg_order_amount: parseFloat(row.avg_order_amount) || 0 })); } catch (error) { console.error('Error in getProductAnalytics:', error); throw error; } } }

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