2026-01-09 18:44:45 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\logs
2026-01-09 18:44:45 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:313] - ============================================================
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:316] - ============================================================
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID: 
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:324] - ============================================================
2026-01-09 18:44:45 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动，等待客户端连接...
2026-01-09 18:44:46 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest
2026-01-09 18:44:46 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
2026-01-09 18:44:46 - mcp_services - INFO - [main.py:119] - 初始化查询配置（数据源: local）...
2026-01-09 18:44:46 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
2026-01-09 18:44:46 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
2026-01-09 18:44:46 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
2026-01-09 18:44:47 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 18:44:47 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesBIIntelligentAnalyticsPlatform
2026-01-09 18:44:47 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 18:44:47 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 18:44:47 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesBIIntelligentAnalyticsPlatform",
  "businessDescription": "销售BI智能分析平台：面向订单、发货/退货、客户复购与毛利贡献等核心指标，提供多维汇总、趋势分析与TOP客户洞察。",
  "sqlTemplate": "SELECT DATE(so.order_date_utc) AS order_date, so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name AS sales_person_name, COUNT(DISTINCT so.sales_order_id) AS order_count, SUM(COALESCE(so.deal_amount, 0)) AS order_amount FROM fact_sales_order so LEFT JOIN dim_customer c ON c.customer_id = so.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = so.sales_person_id AND p.is_current = TRUE GROUP BY DATE(so.order_date_utc), so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name ; WITH ship AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), ret AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS return_amount FROM fact_sales_return WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), keys AS ( SELECT ym, customer_id, sales_person_id FROM ship UNION SELECT ym, customer_id, sales_person_id FROM ret ) SELECT k.ym, k.customer_id, c.customer_name, k.sales_person_id, p.person_name AS sales_person_name, COALESCE(s.ship_amount, 0) AS ship_amount, COALESCE(r.return_amount, 0) AS return_amount, (COALESCE(s.ship_amount, 0) - COALESCE(r.return_amount, 0)) AS net_amount FROM keys k LEFT JOIN ship s ON s.ym = k.ym AND s.customer_id IS NOT DISTINCT FROM k.customer_id AND s.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN ret r ON r.ym = k.ym AND r.customer_id IS NOT DISTINCT FROM k.customer_id AND r.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN dim_customer c ON c.customer_id = k.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = k.sales_person_id AND p.is_current = TRUE ; WITH orders AS ( SELECT so.sales_person_id, so.customer_id, COUNT(DISTINCT so.sales_order_id) AS order_cnt FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.sales_person_id, so.customer_id ), rate AS ( SELECT sales_person_id, COUNT(DISTINCT customer_id) AS customer_cnt, SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) AS repeat_customer_cnt, CASE WHEN COUNT(DISTINCT customer_id) > 0 THEN SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT customer_id) ELSE NULL END AS repurchase_rate FROM orders GROUP BY sales_person_id ), avg_rate AS ( SELECT AVG(repurchase_rate) AS avg_repurchase_rate FROM rate WHERE repurchase_rate IS NOT NULL ) SELECT r.sales_person_id, p.person_name AS sales_person_name, r.customer_cnt, r.repeat_customer_cnt, r.repurchase_rate, a.avg_repurchase_rate FROM rate r CROSS JOIN avg_rate a LEFT JOIN dim_person p ON p.person_id = r.sales_person_id AND p.is_current = TRUE WHERE r.repurchase_rate IS NOT NULL AND r.repurchase_rate < a.avg_repurchase_rate ORDER BY (a.avg_repurchase_rate - r.repurchase_rate) DESC ; WITH revenue AS ( SELECT so.customer_id, SUM(COALESCE(so.deal_amount, 0)) AS revenue_amount FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ), cost AS ( SELECT so.customer_id, SUM(COALESCE(ABS(m.movement_qty) * m.unit_price, 0)) AS cost_amount FROM fact_inventory_movement m JOIN fact_sales_order so ON so.sales_order_id = m.sales_order_id WHERE m.sales_order_id IS NOT NULL AND COALESCE(m.movement_qty, 0) < 0 AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ) SELECT r.customer_id, c.customer_name, r.revenue_amount, COALESCE(k.cost_amount, 0) AS cost_amount, (r.revenue_amount - COALESCE(k.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.revenue_amount > 0 THEN (r.revenue_amount - COALESCE(k.cost_amount, 0)) / r.revenue_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost k ON k.customer_id = r.customer_id LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE ORDER BY gross_profit_amount DESC LIMIT 10 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 18:44:47 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 18:44:47 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 18:44:47 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 18:49:19 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 18:49:19 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesPerformanceIntelligentStatistics
2026-01-09 18:49:19 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 18:49:19 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 18:49:19 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesPerformanceIntelligentStatistics",
  "businessDescription": "销售业绩智能统计系统：基于订单成交与合同归属，计算首触/跟进/协同的贡献度分摊，并据此估算推荐佣金与人员贡献排名。",
  "sqlTemplate": "WITH deal AS ( SELECT so.sales_order_id AS deal_id, so.contract_id, so.customer_id, so.sales_person_id, so.deal_amount, so.order_date_utc AS deal_time_utc FROM fact_sales_order so ), role_first AS ( SELECT d.deal_id, COALESCE(dc.owner_id, d.sales_person_id) AS person_id, 'FIRST_TOUCH' AS role, 0.30 AS role_weight FROM deal d LEFT JOIN dim_contract dc ON dc.contract_id = d.contract_id AND dc.is_current = TRUE ), role_follow AS ( SELECT d.deal_id, d.sales_person_id AS person_id, 'FOLLOW_UP' AS role, 0.50 AS role_weight FROM deal d ), collab_people AS ( SELECT DISTINCT s.contract_id, s.operator_id AS person_id FROM fact_sales_shipment s WHERE s.operator_id IS NOT NULL UNION DISTINCT SELECT DISTINCT i.contract_id, i.handler_id AS person_id FROM fact_invoice i WHERE i.handler_id IS NOT NULL UNION DISTINCT SELECT DISTINCT w.contract_id, w.handler_id AS person_id FROM fact_write_off w WHERE w.handler_id IS NOT NULL ), role_collab AS ( SELECT d.deal_id, cp.person_id, 'COLLAB' AS role, 0.20 AS role_weight FROM deal d JOIN collab_people cp ON cp.contract_id = d.contract_id ), roles_union AS ( SELECT * FROM role_first UNION ALL SELECT * FROM role_follow UNION ALL SELECT * FROM role_collab ), collab_cnt AS ( SELECT deal_id, COUNT(DISTINCT person_id) AS collab_person_cnt FROM role_collab GROUP BY deal_id ), normalized AS ( SELECT ru.deal_id, ru.person_id, ru.role, CASE WHEN ru.role = 'COLLAB' THEN ru.role_weight / NULLIF(cc.collab_person_cnt, 0) ELSE ru.role_weight END AS contribution_pct FROM roles_union ru LEFT JOIN collab_cnt cc ON cc.deal_id = ru.deal_id ) SELECT n.deal_id, n.person_id, n.role, n.contribution_pct FROM normalized n ; WITH deal AS ( SELECT so.sales_order_id AS deal_id, so.contract_id, so.customer_id, so.deal_amount, so.order_date_utc AS deal_time_utc FROM fact_sales_order so ), contrib AS ( WITH role_first AS ( SELECT d.deal_id, COALESCE(dc.owner_id, so.sales_person_id) AS person_id, 'FIRST_TOUCH' AS role, 0.30 AS role_weight FROM deal d JOIN fact_sales_order so ON so.sales_order_id = d.deal_id LEFT JOIN dim_contract dc ON dc.contract_id = d.contract_id AND dc.is_current = TRUE ), role_follow AS ( SELECT d.deal_id, so.sales_person_id AS person_id, 'FOLLOW_UP' AS role, 0.50 AS role_weight FROM deal d JOIN fact_sales_order so ON so.sales_order_id = d.deal_id ), collab_people AS ( SELECT DISTINCT s.contract_id, s.operator_id AS person_id FROM fact_sales_shipment s WHERE s.operator_id IS NOT NULL UNION DISTINCT SELECT DISTINCT i.contract_id, i.handler_id AS person_id FROM fact_invoice i WHERE i.handler_id IS NOT NULL UNION DISTINCT SELECT DISTINCT w.contract_id, w.handler_id AS person_id FROM fact_write_off w WHERE w.handler_id IS NOT NULL ), role_collab AS ( SELECT d.deal_id, cp.person_id, 'COLLAB' AS role, 0.20 AS role_weight FROM deal d JOIN collab_people cp ON cp.contract_id = d.contract_id ), roles_union AS ( SELECT * FROM role_first UNION ALL SELECT * FROM role_follow UNION ALL SELECT * FROM role_collab ), collab_cnt AS ( SELECT deal_id, COUNT(DISTINCT person_id) AS collab_person_cnt FROM role_collab GROUP BY deal_id ) SELECT ru.deal_id, ru.person_id, ru.role, CASE WHEN ru.role = 'COLLAB' THEN ru.role_weight / NULLIF(cc.collab_person_cnt, 0) ELSE ru.role_weight END AS contribution_pct FROM roles_union ru LEFT JOIN collab_cnt cc ON cc.deal_id = ru.deal_id ) SELECT d.deal_id, d.deal_time_utc, d.contract_id, d.customer_id, c.customer_name, co.person_id, p.person_name, co.role, co.contribution_pct, d.deal_amount, (d.deal_amount * 0.05 * co.contribution_pct) AS recommend_commission_amount FROM deal d JOIN contrib co ON co.deal_id = d.deal_id LEFT JOIN dim_customer c ON c.customer_id = d.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = co.person_id AND p.is_current = TRUE ORDER BY d.deal_time_utc DESC, d.deal_id, co.contribution_pct DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 18:49:19 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 18:49:19 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 18:49:19 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 18:49:24 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 18:49:24 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: FinancialAnalyticsDashboard
2026-01-09 18:49:24 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 18:49:24 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 18:49:24 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "FinancialAnalyticsDashboard",
  "businessDescription": "财务数据分析看板：覆盖应收/应付月度趋势、现金流收支、逾期应收预警，以及销售毛利与毛利率的月度拆解。",
  "sqlTemplate": "SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ar_amount, SUM(COALESCE(written_off_amount, 0)) AS ar_written_off_amount, SUM(COALESCE(unwritten_off_amount, 0)) AS ar_unwritten_off_amount FROM fact_ar_receipt WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ORDER BY ym ; SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ap_amount, SUM(COALESCE(written_off_amount, 0)) AS ap_written_off_amount, SUM(COALESCE(unwritten_off_amount, 0)) AS ap_unwritten_off_amount FROM fact_ap_payment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ORDER BY ym ; SELECT DATE(doc_date_utc) AS d, SUM(COALESCE(income_amount, 0)) AS cash_in, SUM(COALESCE(expense_amount, 0)) AS cash_out, SUM(COALESCE(income_amount, 0)) - SUM(COALESCE(expense_amount, 0)) AS net_cash FROM fact_cash_flow WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '60 days' GROUP BY DATE(doc_date_utc) ORDER BY d ; SELECT r.customer_id, c.customer_name, SUM(COALESCE(r.unwritten_off_amount, 0)) AS ar_overdue_balance, MIN(DATE(r.doc_date_utc)) AS oldest_doc_date FROM fact_ar_receipt r LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE WHERE COALESCE(r.unwritten_off_amount, 0) > 0 AND (CURRENT_DATE - DATE(r.doc_date_utc)) > 60 GROUP BY r.customer_id, c.customer_name ORDER BY ar_overdue_balance DESC ; WITH revenue AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ), cost AS ( SELECT to_char(event_time_utc, 'YYYY-MM') AS ym, SUM(COALESCE(ABS(movement_qty) * unit_price, 0)) AS cost_amount FROM fact_inventory_movement WHERE sales_order_id IS NOT NULL AND COALESCE(movement_qty, 0) < 0 AND event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(event_time_utc, 'YYYY-MM') ) SELECT r.ym, r.ship_amount, c.cost_amount, (r.ship_amount - COALESCE(c.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.ship_amount > 0 THEN (r.ship_amount - COALESCE(c.cost_amount, 0)) / r.ship_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost c ON c.ym = r.ym ORDER BY r.ym ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 18:49:24 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 18:49:24 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 18:49:24 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 18:49:27 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 18:49:27 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SmartCostPredictionModel
2026-01-09 18:49:27 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 18:49:27 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 18:49:27 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SmartCostPredictionModel",
  "businessDescription": "智能成本预测模型：基于历史入库单价估算原材料基准成本，结合BOM用量拆解标准成本结构，并支持原材涨跌价情景推演。",
  "sqlTemplate": "WITH raw_in AS ( SELECT m.product_id, SUM(COALESCE(m.movement_qty, 0)) AS in_qty, SUM(COALESCE(m.movement_qty, 0) * COALESCE(m.unit_price, 0)) AS in_amount FROM fact_inventory_movement m WHERE m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND COALESCE(m.movement_qty, 0) > 0 AND COALESCE(m.unit_price, 0) > 0 GROUP BY m.product_id ) SELECT p.product_code, p.product_name, CASE WHEN ri.in_qty > 0 THEN ri.in_amount / ri.in_qty ELSE NULL END AS base_unit_cost FROM dim_product p LEFT JOIN raw_in ri ON ri.product_id = p.product_id WHERE p.is_current = TRUE AND p.product_type = 'RAW' ; WITH bom_min_level AS ( SELECT bom_number, MIN(COALESCE(level_number, 0)) AS min_level FROM dim_bom WHERE is_current = TRUE GROUP BY bom_number ), parent AS ( SELECT b.bom_number, b.product_code AS parent_product_code FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) = ml.min_level WHERE b.is_current = TRUE ), component AS ( SELECT b.bom_number, b.product_code AS component_product_code, COALESCE(b.unit_usage_qty, 0) AS unit_usage_qty FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) > ml.min_level WHERE b.is_current = TRUE ) SELECT p.bom_number, p.parent_product_code, c.component_product_code, c.unit_usage_qty FROM parent p JOIN component c ON c.bom_number = p.bom_number ORDER BY p.parent_product_code, c.component_product_code ; WITH raw_price AS ( SELECT p.product_code, CASE WHEN SUM(COALESCE(m.movement_qty, 0)) > 0 THEN SUM(COALESCE(m.movement_qty, 0) * COALESCE(m.unit_price, 0)) / SUM(COALESCE(m.movement_qty, 0)) ELSE NULL END AS base_unit_cost FROM dim_product p LEFT JOIN fact_inventory_movement m ON m.product_id = p.product_id AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND COALESCE(m.movement_qty, 0) > 0 AND COALESCE(m.unit_price, 0) > 0 WHERE p.is_current = TRUE AND p.product_type = 'RAW' GROUP BY p.product_code ), bom_min_level AS ( SELECT bom_number, MIN(COALESCE(level_number, 0)) AS min_level FROM dim_bom WHERE is_current = TRUE GROUP BY bom_number ), parent AS ( SELECT b.bom_number, b.product_code AS parent_product_code FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) = ml.min_level WHERE b.is_current = TRUE ), component AS ( SELECT b.bom_number, b.product_code AS component_product_code, COALESCE(b.unit_usage_qty, 0) AS unit_usage_qty FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) > ml.min_level WHERE b.is_current = TRUE ), line_cost AS ( SELECT p.parent_product_code, c.component_product_code, c.unit_usage_qty, rp.base_unit_cost, (c.unit_usage_qty * rp.base_unit_cost) AS component_cost FROM parent p JOIN component c ON c.bom_number = p.bom_number LEFT JOIN raw_price rp ON rp.product_code = c.component_product_code ), total_cost AS ( SELECT parent_product_code, SUM(COALESCE(component_cost, 0)) AS standard_cost FROM line_cost GROUP BY parent_product_code ) SELECT lc.parent_product_code, lc.component_product_code, lc.unit_usage_qty, lc.base_unit_cost, lc.component_cost, tc.standard_cost, CASE WHEN tc.standard_cost > 0 THEN lc.component_cost / tc.standard_cost ELSE NULL END AS cost_share FROM line_cost lc JOIN total_cost tc ON tc.parent_product_code = lc.parent_product_code ORDER BY lc.parent_product_code, cost_share DESC ; WITH scenario AS ( SELECT 'RAW-001' AS material_product_code, 0.10 AS delta_pct ), raw_price AS ( SELECT p.product_code, CASE WHEN SUM(COALESCE(m.movement_qty, 0)) > 0 THEN SUM(COALESCE(m.movement_qty, 0) * COALESCE(m.unit_price, 0)) / SUM(COALESCE(m.movement_qty, 0)) ELSE NULL END AS base_unit_cost FROM dim_product p LEFT JOIN fact_inventory_movement m ON m.product_id = p.product_id AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND COALESCE(m.movement_qty, 0) > 0 AND COALESCE(m.unit_price, 0) > 0 WHERE p.is_current = TRUE AND p.product_type = 'RAW' GROUP BY p.product_code ), bom_min_level AS ( SELECT bom_number, MIN(COALESCE(level_number, 0)) AS min_level FROM dim_bom WHERE is_current = TRUE GROUP BY bom_number ), parent AS ( SELECT b.bom_number, b.product_code AS parent_product_code FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) = ml.min_level WHERE b.is_current = TRUE ), component AS ( SELECT b.bom_number, b.product_code AS component_product_code, COALESCE(b.unit_usage_qty, 0) AS unit_usage_qty FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) > ml.min_level WHERE b.is_current = TRUE ), line_cost AS ( SELECT p.parent_product_code, c.component_product_code, c.unit_usage_qty, rp.base_unit_cost, (c.unit_usage_qty * rp.base_unit_cost) AS component_cost FROM parent p JOIN component c ON c.bom_number = p.bom_number LEFT JOIN raw_price rp ON rp.product_code = c.component_product_code ), total_cost AS ( SELECT parent_product_code, SUM(COALESCE(component_cost, 0)) AS standard_cost FROM line_cost GROUP BY parent_product_code ), delta_cost AS ( SELECT lc.parent_product_code, SUM( CASE WHEN lc.component_product_code = s.material_product_code THEN COALESCE(lc.component_cost, 0) * s.delta_pct ELSE 0 END ) AS scenario_cost_delta FROM line_cost lc CROSS JOIN scenario s GROUP BY lc.parent_product_code ) SELECT tc.parent_product_code, tc.standard_cost AS base_standard_cost, dc.scenario_cost_delta, (tc.standard_cost + COALESCE(dc.scenario_cost_delta, 0)) AS new_standard_cost FROM total_cost tc LEFT JOIN delta_cost dc ON dc.parent_product_code = tc.parent_product_code ORDER BY dc.scenario_cost_delta DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 18:49:27 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 18:49:27 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 18:49:27 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 18:57:52 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 18:57:52 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesBIIntelligentAnalyticsPlatform
2026-01-09 18:57:52 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 18:57:52 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 18:57:52 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesBIIntelligentAnalyticsPlatform",
  "businessDescription": "销售BI智能分析平台：面向订单、发货/退货、客户复购与毛利贡献等核心指标，提供多维汇总、趋势分析与TOP客户洞察。",
  "sqlTemplate": "SELECT DATE(so.order_date_utc) AS order_date, so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name AS sales_person_name, COUNT(DISTINCT so.sales_order_id) AS order_count, SUM(COALESCE(so.deal_amount, 0)) AS order_amount FROM fact_sales_order so LEFT JOIN dim_customer c ON c.customer_id = so.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = so.sales_person_id AND p.is_current = TRUE GROUP BY DATE(so.order_date_utc), so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name ; WITH ship AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), ret AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS return_amount FROM fact_sales_return WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), keys AS ( SELECT ym, customer_id, sales_person_id FROM ship UNION SELECT ym, customer_id, sales_person_id FROM ret ) SELECT k.ym, k.customer_id, c.customer_name, k.sales_person_id, p.person_name AS sales_person_name, COALESCE(s.ship_amount, 0) AS ship_amount, COALESCE(r.return_amount, 0) AS return_amount, (COALESCE(s.ship_amount, 0) - COALESCE(r.return_amount, 0)) AS net_amount FROM keys k LEFT JOIN ship s ON s.ym = k.ym AND s.customer_id IS NOT DISTINCT FROM k.customer_id AND s.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN ret r ON r.ym = k.ym AND r.customer_id IS NOT DISTINCT FROM k.customer_id AND r.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN dim_customer c ON c.customer_id = k.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = k.sales_person_id AND p.is_current = TRUE ; WITH orders AS ( SELECT so.sales_person_id, so.customer_id, COUNT(DISTINCT so.sales_order_id) AS order_cnt FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.sales_person_id, so.customer_id ), rate AS ( SELECT sales_person_id, COUNT(DISTINCT customer_id) AS customer_cnt, SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) AS repeat_customer_cnt, CASE WHEN COUNT(DISTINCT customer_id) > 0 THEN SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT customer_id) ELSE NULL END AS repurchase_rate FROM orders GROUP BY sales_person_id ), avg_rate AS ( SELECT AVG(repurchase_rate) AS avg_repurchase_rate FROM rate WHERE repurchase_rate IS NOT NULL ) SELECT r.sales_person_id, p.person_name AS sales_person_name, r.customer_cnt, r.repeat_customer_cnt, r.repurchase_rate, a.avg_repurchase_rate FROM rate r CROSS JOIN avg_rate a LEFT JOIN dim_person p ON p.person_id = r.sales_person_id AND p.is_current = TRUE WHERE r.repurchase_rate IS NOT NULL AND r.repurchase_rate < a.avg_repurchase_rate ORDER BY (a.avg_repurchase_rate - r.repurchase_rate) DESC ; WITH revenue AS ( SELECT so.customer_id, SUM(COALESCE(so.deal_amount, 0)) AS revenue_amount FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ), cost AS ( SELECT so.customer_id, SUM(COALESCE(ABS(m.movement_qty) * m.unit_price, 0)) AS cost_amount FROM fact_inventory_movement m JOIN fact_sales_order so ON so.sales_order_id = m.sales_order_id WHERE m.sales_order_id IS NOT NULL AND COALESCE(m.movement_qty, 0) < 0 AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ) SELECT r.customer_id, c.customer_name, r.revenue_amount, COALESCE(k.cost_amount, 0) AS cost_amount, (r.revenue_amount - COALESCE(k.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.revenue_amount > 0 THEN (r.revenue_amount - COALESCE(k.cost_amount, 0)) / r.revenue_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost k ON k.customer_id = r.customer_id LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE ORDER BY gross_profit_amount DESC LIMIT 10 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 18:57:52 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 18:57:52 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 18:57:52 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 18:58:07 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 18:58:07 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SupplierEvaluationAndSmartReplenishment
2026-01-09 18:58:07 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 18:58:07 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 18:58:07 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SupplierEvaluationAndSmartReplenishment",
  "businessDescription": "供应商评估与智能补货：基于物料消耗、交付周期、到货准时率与来料质检结果，输出供应商绩效指标与安全库存/再订货点/建议补货量。",
  "sqlTemplate": "WITH mat_out AS ( SELECT product_id, DATE(event_time_utc) AS d, SUM(CASE WHEN doc_type IN ('OUT','OTHER_OUT') THEN ABS(COALESCE(movement_qty, 0)) ELSE 0 END) AS daily_consume FROM fact_inventory_movement WHERE event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '90 days' GROUP BY product_id, DATE(event_time_utc) ), stats AS ( SELECT product_id, AVG(daily_consume) AS avg_daily_consume, STDDEV_POP(daily_consume) AS std_daily_consume FROM mat_out GROUP BY product_id ) SELECT p.product_code, p.product_name, p.uom_code, s.avg_daily_consume, s.std_daily_consume FROM stats s JOIN dim_product p ON p.product_id = s.product_id AND p.is_current = TRUE WHERE p.product_type = 'RAW' ; WITH lead_time AS ( SELECT po.supplier_id, (DATE(pr.doc_date_utc) - DATE(po.doc_date_utc)) AS lead_days, CASE WHEN po.delivery_date_utc IS NOT NULL AND pr.doc_date_utc IS NOT NULL THEN CASE WHEN DATE(pr.doc_date_utc) <= DATE(po.delivery_date_utc) THEN 1 ELSE 0 END ELSE NULL END AS is_ontime FROM fact_purchase_order po JOIN fact_purchase_receipt pr ON pr.purchase_order_number = po.purchase_order_number WHERE po.doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND pr.doc_date_utc IS NOT NULL ), quality AS ( SELECT supplier_id, SUM(COALESCE(pass_qty, 0)) AS pass_qty, SUM(COALESCE(fail_qty, 0)) AS fail_qty FROM fact_quality_inspection WHERE qc_type = 'INCOMING' AND event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY supplier_id ), agg AS ( SELECT supplier_id, AVG(lead_days) AS avg_lead_days, STDDEV_POP(lead_days) AS std_lead_days, AVG(is_ontime) AS ontime_rate FROM lead_time WHERE lead_days IS NOT NULL AND lead_days >= 0 GROUP BY supplier_id ) SELECT s.supplier_id, s.supplier_name, a.avg_lead_days, a.std_lead_days, a.ontime_rate, CASE WHEN (COALESCE(q.pass_qty, 0) + COALESCE(q.fail_qty, 0)) > 0 THEN COALESCE(q.pass_qty, 0) / (COALESCE(q.pass_qty, 0) + COALESCE(q.fail_qty, 0)) ELSE NULL END AS incoming_pass_rate FROM agg a LEFT JOIN dim_supplier s ON s.supplier_id = a.supplier_id AND s.is_current = TRUE LEFT JOIN quality q ON q.supplier_id = a.supplier_id ORDER BY s.supplier_name ; WITH params AS ( SELECT 1.65::numeric AS z, 7::int AS review_days ), consume_daily AS ( SELECT product_id, DATE(event_time_utc) AS d, SUM(CASE WHEN doc_type IN ('OUT','OTHER_OUT') THEN ABS(COALESCE(movement_qty, 0)) ELSE 0 END) AS daily_consume FROM fact_inventory_movement WHERE event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '90 days' GROUP BY product_id, DATE(event_time_utc) ), consume_stats AS ( SELECT product_id, AVG(daily_consume) AS avg_daily_consume, STDDEV_POP(daily_consume) AS std_daily_consume FROM consume_daily GROUP BY product_id ), lead_time AS ( SELECT pr.supplier_id, AVG((DATE(pr.doc_date_utc) - DATE(po.doc_date_utc))) AS avg_lead_days, STDDEV_POP((DATE(pr.doc_date_utc) - DATE(po.doc_date_utc))) AS std_lead_days FROM fact_purchase_order po JOIN fact_purchase_receipt pr ON pr.purchase_order_number = po.purchase_order_number WHERE po.doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND pr.doc_date_utc IS NOT NULL GROUP BY pr.supplier_id ), latest_onhand_row AS ( SELECT m.product_id, m.warehouse_id, m.onhand_qty_after, ROW_NUMBER() OVER (PARTITION BY m.product_id, m.warehouse_id ORDER BY m.event_time_utc DESC, m.inventory_movement_id DESC) AS rn FROM fact_inventory_movement m WHERE m.product_id IS NOT NULL ), onhand AS ( SELECT product_id, SUM(COALESCE(onhand_qty_after, 0)) AS onhand_qty FROM latest_onhand_row WHERE rn = 1 GROUP BY product_id ), product_supplier AS ( SELECT p.product_id, p.product_code, p.product_name, b.supplier_name FROM dim_product p LEFT JOIN dim_bom b ON b.product_code = p.product_code AND b.is_current = TRUE WHERE p.is_current = TRUE AND p.product_type = 'RAW' ), supplier_id_map AS ( SELECT supplier_id, supplier_name FROM dim_supplier WHERE is_current = TRUE ), merged AS ( SELECT ps.product_id, ps.product_code, ps.product_name, sm.supplier_id, COALESCE(cs.avg_daily_consume, 0) AS avg_daily_consume, COALESCE(cs.std_daily_consume, 0) AS std_daily_consume, COALESCE(lt.avg_lead_days, 0) AS avg_lead_days, COALESCE(lt.std_lead_days, 0) AS std_lead_days, COALESCE(oh.onhand_qty, 0) AS onhand_qty FROM product_supplier ps LEFT JOIN supplier_id_map sm ON sm.supplier_name IS NOT DISTINCT FROM ps.supplier_name LEFT JOIN consume_stats cs ON cs.product_id = ps.product_id LEFT JOIN lead_time lt ON lt.supplier_id = sm.supplier_id LEFT JOIN onhand oh ON oh.product_id = ps.product_id ) SELECT product_code, product_name, onhand_qty, avg_daily_consume, std_daily_consume, avg_lead_days, (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) AS safety_stock_qty, (avg_daily_consume * (avg_lead_days + params.review_days)) + (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) AS reorder_point_qty, GREATEST( 0, (avg_daily_consume * (avg_lead_days + params.review_days)) + (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) - onhand_qty ) AS suggest_order_qty, supplier_id FROM merged CROSS JOIN params ORDER BY suggest_order_qty DESC, product_code ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 18:58:07 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 18:58:07 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 18:58:07 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 18:58:13 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 18:58:13 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesBIIntelligentAnalyticsPlatform
2026-01-09 18:58:13 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 18:58:13 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 18:58:13 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesBIIntelligentAnalyticsPlatform",
  "businessDescription": "销售BI智能分析平台：面向订单、发货/退货、客户复购与毛利贡献等核心指标，提供多维汇总、趋势分析与TOP客户洞察。",
  "sqlTemplate": "SELECT DATE(so.order_date_utc) AS order_date, so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name AS sales_person_name, COUNT(DISTINCT so.sales_order_id) AS order_count, SUM(COALESCE(so.deal_amount, 0)) AS order_amount FROM fact_sales_order so LEFT JOIN dim_customer c ON c.customer_id = so.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = so.sales_person_id AND p.is_current = TRUE GROUP BY DATE(so.order_date_utc), so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name ; WITH ship AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), ret AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS return_amount FROM fact_sales_return WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), keys AS ( SELECT ym, customer_id, sales_person_id FROM ship UNION SELECT ym, customer_id, sales_person_id FROM ret ) SELECT k.ym, k.customer_id, c.customer_name, k.sales_person_id, p.person_name AS sales_person_name, COALESCE(s.ship_amount, 0) AS ship_amount, COALESCE(r.return_amount, 0) AS return_amount, (COALESCE(s.ship_amount, 0) - COALESCE(r.return_amount, 0)) AS net_amount FROM keys k LEFT JOIN ship s ON s.ym = k.ym AND s.customer_id IS NOT DISTINCT FROM k.customer_id AND s.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN ret r ON r.ym = k.ym AND r.customer_id IS NOT DISTINCT FROM k.customer_id AND r.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN dim_customer c ON c.customer_id = k.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = k.sales_person_id AND p.is_current = TRUE ; WITH orders AS ( SELECT so.sales_person_id, so.customer_id, COUNT(DISTINCT so.sales_order_id) AS order_cnt FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.sales_person_id, so.customer_id ), rate AS ( SELECT sales_person_id, COUNT(DISTINCT customer_id) AS customer_cnt, SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) AS repeat_customer_cnt, CASE WHEN COUNT(DISTINCT customer_id) > 0 THEN SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT customer_id) ELSE NULL END AS repurchase_rate FROM orders GROUP BY sales_person_id ), avg_rate AS ( SELECT AVG(repurchase_rate) AS avg_repurchase_rate FROM rate WHERE repurchase_rate IS NOT NULL ) SELECT r.sales_person_id, p.person_name AS sales_person_name, r.customer_cnt, r.repeat_customer_cnt, r.repurchase_rate, a.avg_repurchase_rate FROM rate r CROSS JOIN avg_rate a LEFT JOIN dim_person p ON p.person_id = r.sales_person_id AND p.is_current = TRUE WHERE r.repurchase_rate IS NOT NULL AND r.repurchase_rate < a.avg_repurchase_rate ORDER BY (a.avg_repurchase_rate - r.repurchase_rate) DESC ; WITH revenue AS ( SELECT so.customer_id, SUM(COALESCE(so.deal_amount, 0)) AS revenue_amount FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ), cost AS ( SELECT so.customer_id, SUM(COALESCE(ABS(m.movement_qty) * m.unit_price, 0)) AS cost_amount FROM fact_inventory_movement m JOIN fact_sales_order so ON so.sales_order_id = m.sales_order_id WHERE m.sales_order_id IS NOT NULL AND COALESCE(m.movement_qty, 0) < 0 AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ) SELECT r.customer_id, c.customer_name, r.revenue_amount, COALESCE(k.cost_amount, 0) AS cost_amount, (r.revenue_amount - COALESCE(k.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.revenue_amount > 0 THEN (r.revenue_amount - COALESCE(k.cost_amount, 0)) / r.revenue_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost k ON k.customer_id = r.customer_id LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE ORDER BY gross_profit_amount DESC LIMIT 10 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 18:58:13 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 18:58:13 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 18:58:13 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:02:47 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:02:47 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesBIIntelligentAnalyticsPlatform
2026-01-09 19:02:47 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:02:47 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:02:47 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesBIIntelligentAnalyticsPlatform",
  "businessDescription": "销售BI智能分析平台：面向订单、发货/退货、客户复购与毛利贡献等核心指标，提供多维汇总、趋势分析与TOP客户洞察。",
  "sqlTemplate": "SELECT DATE(so.order_date_utc) AS order_date, so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name AS sales_person_name, COUNT(DISTINCT so.sales_order_id) AS order_count, SUM(COALESCE(so.deal_amount, 0)) AS order_amount FROM fact_sales_order so LEFT JOIN dim_customer c ON c.customer_id = so.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = so.sales_person_id AND p.is_current = TRUE GROUP BY DATE(so.order_date_utc), so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name ; WITH ship AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), ret AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS return_amount FROM fact_sales_return WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), keys AS ( SELECT ym, customer_id, sales_person_id FROM ship UNION SELECT ym, customer_id, sales_person_id FROM ret ) SELECT k.ym, k.customer_id, c.customer_name, k.sales_person_id, p.person_name AS sales_person_name, COALESCE(s.ship_amount, 0) AS ship_amount, COALESCE(r.return_amount, 0) AS return_amount, (COALESCE(s.ship_amount, 0) - COALESCE(r.return_amount, 0)) AS net_amount FROM keys k LEFT JOIN ship s ON s.ym = k.ym AND s.customer_id IS NOT DISTINCT FROM k.customer_id AND s.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN ret r ON r.ym = k.ym AND r.customer_id IS NOT DISTINCT FROM k.customer_id AND r.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN dim_customer c ON c.customer_id = k.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = k.sales_person_id AND p.is_current = TRUE ; WITH orders AS ( SELECT so.sales_person_id, so.customer_id, COUNT(DISTINCT so.sales_order_id) AS order_cnt FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.sales_person_id, so.customer_id ), rate AS ( SELECT sales_person_id, COUNT(DISTINCT customer_id) AS customer_cnt, SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) AS repeat_customer_cnt, CASE WHEN COUNT(DISTINCT customer_id) > 0 THEN SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT customer_id) ELSE NULL END AS repurchase_rate FROM orders GROUP BY sales_person_id ), avg_rate AS ( SELECT AVG(repurchase_rate) AS avg_repurchase_rate FROM rate WHERE repurchase_rate IS NOT NULL ) SELECT r.sales_person_id, p.person_name AS sales_person_name, r.customer_cnt, r.repeat_customer_cnt, r.repurchase_rate, a.avg_repurchase_rate FROM rate r CROSS JOIN avg_rate a LEFT JOIN dim_person p ON p.person_id = r.sales_person_id AND p.is_current = TRUE WHERE r.repurchase_rate IS NOT NULL AND r.repurchase_rate < a.avg_repurchase_rate ORDER BY (a.avg_repurchase_rate - r.repurchase_rate) DESC ; WITH revenue AS ( SELECT so.customer_id, SUM(COALESCE(so.deal_amount, 0)) AS revenue_amount FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ), cost AS ( SELECT so.customer_id, SUM(COALESCE(ABS(m.movement_qty) * m.unit_price, 0)) AS cost_amount FROM fact_inventory_movement m JOIN fact_sales_order so ON so.sales_order_id = m.sales_order_id WHERE m.sales_order_id IS NOT NULL AND COALESCE(m.movement_qty, 0) < 0 AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ) SELECT r.customer_id, c.customer_name, r.revenue_amount, COALESCE(k.cost_amount, 0) AS cost_amount, (r.revenue_amount - COALESCE(k.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.revenue_amount > 0 THEN (r.revenue_amount - COALESCE(k.cost_amount, 0)) / r.revenue_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost k ON k.customer_id = r.customer_id LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE ORDER BY gross_profit_amount DESC LIMIT 10 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:02:47 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:02:47 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:02:47 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:31:56 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\logs
2026-01-09 19:31:56 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:313] - ============================================================
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:316] - ============================================================
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID: 
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:324] - ============================================================
2026-01-09 19:31:56 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动，等待客户端连接...
2026-01-09 19:31:58 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest
2026-01-09 19:31:58 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
2026-01-09 19:31:58 - mcp_services - INFO - [main.py:119] - 初始化查询配置（数据源: local）...
2026-01-09 19:31:58 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
2026-01-09 19:31:58 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
2026-01-09 19:31:58 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
2026-01-09 19:32:01 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:32:01 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SupplierEvaluationAndSmartReplenishment
2026-01-09 19:32:01 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:32:01 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:32:01 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SupplierEvaluationAndSmartReplenishment",
  "businessDescription": "供应商评估与智能补货：基于物料消耗、交付周期、到货准时率与来料质检结果，输出供应商绩效指标与安全库存/再订货点/建议补货量。",
  "sqlTemplate": "WITH mat_out AS ( SELECT product_id, DATE(event_time_utc) AS d, SUM(CASE WHEN doc_type IN ('OUT','OTHER_OUT') THEN ABS(COALESCE(movement_qty, 0)) ELSE 0 END) AS daily_consume FROM fact_inventory_movement WHERE event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '90 days' GROUP BY product_id, DATE(event_time_utc) ), stats AS ( SELECT product_id, AVG(daily_consume) AS avg_daily_consume, STDDEV_POP(daily_consume) AS std_daily_consume FROM mat_out GROUP BY product_id ) SELECT p.product_code, p.product_name, p.uom_code, s.avg_daily_consume, s.std_daily_consume FROM stats s JOIN dim_product p ON p.product_id = s.product_id AND p.is_current = TRUE WHERE p.product_type = '标准产品' ; WITH lead_time AS ( SELECT po.supplier_id, (DATE(pr.doc_date_utc) - DATE(po.doc_date_utc)) AS lead_days, CASE WHEN po.delivery_date_utc IS NOT NULL AND pr.doc_date_utc IS NOT NULL THEN CASE WHEN DATE(pr.doc_date_utc) <= DATE(po.delivery_date_utc) THEN 1 ELSE 0 END ELSE NULL END AS is_ontime FROM fact_purchase_order po JOIN fact_purchase_receipt pr ON pr.purchase_order_number = po.purchase_order_number WHERE po.doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND pr.doc_date_utc IS NOT NULL ), quality AS ( SELECT supplier_id, SUM(COALESCE(pass_qty, 0)) AS pass_qty, SUM(COALESCE(fail_qty, 0)) AS fail_qty FROM fact_quality_inspection WHERE qc_type = 'INCOMING' AND event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY supplier_id ), agg AS ( SELECT supplier_id, AVG(lead_days) AS avg_lead_days, STDDEV_POP(lead_days) AS std_lead_days, AVG(is_ontime) AS ontime_rate FROM lead_time WHERE lead_days IS NOT NULL AND lead_days >= 0 GROUP BY supplier_id ) SELECT s.supplier_id, s.supplier_name, a.avg_lead_days, a.std_lead_days, a.ontime_rate, CASE WHEN (COALESCE(q.pass_qty, 0) + COALESCE(q.fail_qty, 0)) > 0 THEN COALESCE(q.pass_qty, 0) / (COALESCE(q.pass_qty, 0) + COALESCE(q.fail_qty, 0)) ELSE NULL END AS incoming_pass_rate FROM agg a LEFT JOIN dim_supplier s ON s.supplier_id = a.supplier_id AND s.is_current = TRUE LEFT JOIN quality q ON q.supplier_id = a.supplier_id ORDER BY s.supplier_name ; WITH params AS ( SELECT 1.65::numeric AS z, 7::int AS review_days ), consume_daily AS ( SELECT product_id, DATE(event_time_utc) AS d, SUM(CASE WHEN doc_type IN ('OUT','OTHER_OUT') THEN ABS(COALESCE(movement_qty, 0)) ELSE 0 END) AS daily_consume FROM fact_inventory_movement WHERE event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '90 days' GROUP BY product_id, DATE(event_time_utc) ), consume_stats AS ( SELECT product_id, AVG(daily_consume) AS avg_daily_consume, STDDEV_POP(daily_consume) AS std_daily_consume FROM consume_daily GROUP BY product_id ), lead_time AS ( SELECT pr.supplier_id, AVG((DATE(pr.doc_date_utc) - DATE(po.doc_date_utc))) AS avg_lead_days, STDDEV_POP((DATE(pr.doc_date_utc) - DATE(po.doc_date_utc))) AS std_lead_days FROM fact_purchase_order po JOIN fact_purchase_receipt pr ON pr.purchase_order_number = po.purchase_order_number WHERE po.doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND pr.doc_date_utc IS NOT NULL GROUP BY pr.supplier_id ), latest_onhand_row AS ( SELECT m.product_id, m.warehouse_id, m.onhand_qty_after, ROW_NUMBER() OVER (PARTITION BY m.product_id, m.warehouse_id ORDER BY m.event_time_utc DESC, m.inventory_movement_id DESC) AS rn FROM fact_inventory_movement m WHERE m.product_id IS NOT NULL ), onhand AS ( SELECT product_id, SUM(COALESCE(onhand_qty_after, 0)) AS onhand_qty FROM latest_onhand_row WHERE rn = 1 GROUP BY product_id ), product_supplier AS ( SELECT p.product_id, p.product_code, p.product_name, b.supplier_name FROM dim_product p LEFT JOIN dim_bom b ON b.product_code = p.product_code AND b.is_current = TRUE WHERE p.is_current = TRUE AND p.product_type = '标准产品' ), supplier_id_map AS ( SELECT supplier_id, supplier_name FROM dim_supplier WHERE is_current = TRUE ), merged AS ( SELECT ps.product_id, ps.product_code, ps.product_name, sm.supplier_id, COALESCE(cs.avg_daily_consume, 0) AS avg_daily_consume, COALESCE(cs.std_daily_consume, 0) AS std_daily_consume, COALESCE(lt.avg_lead_days, 0) AS avg_lead_days, COALESCE(lt.std_lead_days, 0) AS std_lead_days, COALESCE(oh.onhand_qty, 0) AS onhand_qty FROM product_supplier ps LEFT JOIN supplier_id_map sm ON sm.supplier_name IS NOT DISTINCT FROM ps.supplier_name LEFT JOIN consume_stats cs ON cs.product_id = ps.product_id LEFT JOIN lead_time lt ON lt.supplier_id = sm.supplier_id LEFT JOIN onhand oh ON oh.product_id = ps.product_id ) SELECT product_code, product_name, onhand_qty, avg_daily_consume, std_daily_consume, avg_lead_days, (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) AS safety_stock_qty, (avg_daily_consume * (avg_lead_days + params.review_days)) + (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) AS reorder_point_qty, GREATEST( 0, (avg_daily_consume * (avg_lead_days + params.review_days)) + (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) - onhand_qty ) AS suggest_order_qty, supplier_id FROM merged CROSS JOIN params ORDER BY suggest_order_qty DESC, product_code ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:32:01 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:32:01 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:32:01 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:32:04 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:32:04 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesBIIntelligentAnalyticsPlatform
2026-01-09 19:32:04 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:32:04 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:32:04 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesBIIntelligentAnalyticsPlatform",
  "businessDescription": "销售BI智能分析平台：面向订单、发货/退货、客户复购与毛利贡献等核心指标，提供多维汇总、趋势分析与TOP客户洞察。",
  "sqlTemplate": "SELECT DATE(so.order_date_utc) AS order_date, so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name AS sales_person_name, COUNT(DISTINCT so.sales_order_id) AS order_count, SUM(COALESCE(so.deal_amount, 0)) AS order_amount FROM fact_sales_order so LEFT JOIN dim_customer c ON c.customer_id = so.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = so.sales_person_id AND p.is_current = TRUE GROUP BY DATE(so.order_date_utc), so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name ; WITH ship AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), ret AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS return_amount FROM fact_sales_return WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), keys AS ( SELECT ym, customer_id, sales_person_id FROM ship UNION SELECT ym, customer_id, sales_person_id FROM ret ) SELECT k.ym, k.customer_id, c.customer_name, k.sales_person_id, p.person_name AS sales_person_name, COALESCE(s.ship_amount, 0) AS ship_amount, COALESCE(r.return_amount, 0) AS return_amount, (COALESCE(s.ship_amount, 0) - COALESCE(r.return_amount, 0)) AS net_amount FROM keys k LEFT JOIN ship s ON s.ym = k.ym AND s.customer_id IS NOT DISTINCT FROM k.customer_id AND s.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN ret r ON r.ym = k.ym AND r.customer_id IS NOT DISTINCT FROM k.customer_id AND r.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN dim_customer c ON c.customer_id = k.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = k.sales_person_id AND p.is_current = TRUE ; WITH orders AS ( SELECT so.sales_person_id, so.customer_id, COUNT(DISTINCT so.sales_order_id) AS order_cnt FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.sales_person_id, so.customer_id ), rate AS ( SELECT sales_person_id, COUNT(DISTINCT customer_id) AS customer_cnt, SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) AS repeat_customer_cnt, CASE WHEN COUNT(DISTINCT customer_id) > 0 THEN SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT customer_id) ELSE NULL END AS repurchase_rate FROM orders GROUP BY sales_person_id ), avg_rate AS ( SELECT AVG(repurchase_rate) AS avg_repurchase_rate FROM rate WHERE repurchase_rate IS NOT NULL ) SELECT r.sales_person_id, p.person_name AS sales_person_name, r.customer_cnt, r.repeat_customer_cnt, r.repurchase_rate, a.avg_repurchase_rate FROM rate r CROSS JOIN avg_rate a LEFT JOIN dim_person p ON p.person_id = r.sales_person_id AND p.is_current = TRUE WHERE r.repurchase_rate IS NOT NULL AND r.repurchase_rate < a.avg_repurchase_rate ORDER BY (a.avg_repurchase_rate - r.repurchase_rate) DESC ; WITH revenue AS ( SELECT so.customer_id, SUM(COALESCE(so.deal_amount, 0)) AS revenue_amount FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ), cost AS ( SELECT so.customer_id, SUM(COALESCE(ABS(m.movement_qty) * m.unit_price, 0)) AS cost_amount FROM fact_inventory_movement m JOIN fact_sales_order so ON so.sales_order_id = m.sales_order_id WHERE m.sales_order_id IS NOT NULL AND COALESCE(m.movement_qty, 0) < 0 AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ) SELECT r.customer_id, c.customer_name, r.revenue_amount, COALESCE(k.cost_amount, 0) AS cost_amount, (r.revenue_amount - COALESCE(k.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.revenue_amount > 0 THEN (r.revenue_amount - COALESCE(k.cost_amount, 0)) / r.revenue_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost k ON k.customer_id = r.customer_id LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE ORDER BY gross_profit_amount DESC LIMIT 10 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:32:04 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:32:04 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:32:04 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:32:07 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:32:07 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesPerformanceIntelligentStatistics
2026-01-09 19:32:07 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:32:07 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:32:07 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesPerformanceIntelligentStatistics",
  "businessDescription": "销售业绩智能统计系统：基于订单成交与合同归属，计算首触/跟进/协同的贡献度分摊，并据此估算推荐佣金与人员贡献排名。",
  "sqlTemplate": "WITH deal AS ( SELECT so.sales_order_id AS deal_id, so.contract_id, so.customer_id, so.sales_person_id, so.deal_amount, so.order_date_utc AS deal_time_utc FROM fact_sales_order so ), role_first AS ( SELECT d.deal_id, COALESCE(dc.owner_id, d.sales_person_id) AS person_id, 'FIRST_TOUCH' AS role, 0.30 AS role_weight FROM deal d LEFT JOIN dim_contract dc ON dc.contract_id = d.contract_id AND dc.is_current = TRUE ), role_follow AS ( SELECT d.deal_id, d.sales_person_id AS person_id, 'FOLLOW_UP' AS role, 0.50 AS role_weight FROM deal d ), collab_people AS ( SELECT DISTINCT s.contract_id, s.operator_id AS person_id FROM fact_sales_shipment s WHERE s.operator_id IS NOT NULL UNION DISTINCT SELECT DISTINCT i.contract_id, i.handler_id AS person_id FROM fact_invoice i WHERE i.handler_id IS NOT NULL UNION DISTINCT SELECT DISTINCT w.contract_id, w.handler_id AS person_id FROM fact_write_off w WHERE w.handler_id IS NOT NULL ), role_collab AS ( SELECT d.deal_id, cp.person_id, 'COLLAB' AS role, 0.20 AS role_weight FROM deal d JOIN collab_people cp ON cp.contract_id = d.contract_id ), roles_union AS ( SELECT * FROM role_first UNION ALL SELECT * FROM role_follow UNION ALL SELECT * FROM role_collab ), collab_cnt AS ( SELECT deal_id, COUNT(DISTINCT person_id) AS collab_person_cnt FROM role_collab GROUP BY deal_id ), normalized AS ( SELECT ru.deal_id, ru.person_id, ru.role, CASE WHEN ru.role = 'COLLAB' THEN ru.role_weight / NULLIF(cc.collab_person_cnt, 0) ELSE ru.role_weight END AS contribution_pct FROM roles_union ru LEFT JOIN collab_cnt cc ON cc.deal_id = ru.deal_id ) SELECT n.deal_id, n.person_id, n.role, n.contribution_pct FROM normalized n ; WITH deal AS ( SELECT so.sales_order_id AS deal_id, so.contract_id, so.customer_id, so.deal_amount, so.order_date_utc AS deal_time_utc FROM fact_sales_order so ), contrib AS ( WITH role_first AS ( SELECT d.deal_id, COALESCE(dc.owner_id, so.sales_person_id) AS person_id, 'FIRST_TOUCH' AS role, 0.30 AS role_weight FROM deal d JOIN fact_sales_order so ON so.sales_order_id = d.deal_id LEFT JOIN dim_contract dc ON dc.contract_id = d.contract_id AND dc.is_current = TRUE ), role_follow AS ( SELECT d.deal_id, so.sales_person_id AS person_id, 'FOLLOW_UP' AS role, 0.50 AS role_weight FROM deal d JOIN fact_sales_order so ON so.sales_order_id = d.deal_id ), collab_people AS ( SELECT DISTINCT s.contract_id, s.operator_id AS person_id FROM fact_sales_shipment s WHERE s.operator_id IS NOT NULL UNION DISTINCT SELECT DISTINCT i.contract_id, i.handler_id AS person_id FROM fact_invoice i WHERE i.handler_id IS NOT NULL UNION DISTINCT SELECT DISTINCT w.contract_id, w.handler_id AS person_id FROM fact_write_off w WHERE w.handler_id IS NOT NULL ), role_collab AS ( SELECT d.deal_id, cp.person_id, 'COLLAB' AS role, 0.20 AS role_weight FROM deal d JOIN collab_people cp ON cp.contract_id = d.contract_id ), roles_union AS ( SELECT * FROM role_first UNION ALL SELECT * FROM role_follow UNION ALL SELECT * FROM role_collab ), collab_cnt AS ( SELECT deal_id, COUNT(DISTINCT person_id) AS collab_person_cnt FROM role_collab GROUP BY deal_id ) SELECT ru.deal_id, ru.person_id, ru.role, CASE WHEN ru.role = 'COLLAB' THEN ru.role_weight / NULLIF(cc.collab_person_cnt, 0) ELSE ru.role_weight END AS contribution_pct FROM roles_union ru LEFT JOIN collab_cnt cc ON cc.deal_id = ru.deal_id ) SELECT d.deal_id, d.deal_time_utc, d.contract_id, d.customer_id, c.customer_name, co.person_id, p.person_name, co.role, co.contribution_pct, d.deal_amount, (d.deal_amount * 0.05 * co.contribution_pct) AS recommend_commission_amount FROM deal d JOIN contrib co ON co.deal_id = d.deal_id LEFT JOIN dim_customer c ON c.customer_id = d.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = co.person_id AND p.is_current = TRUE ORDER BY d.deal_time_utc DESC, d.deal_id, co.contribution_pct DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:32:07 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:32:07 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:32:07 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:32:12 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:32:12 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: FinancialAnalyticsDashboard
2026-01-09 19:32:12 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:32:12 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:32:12 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "FinancialAnalyticsDashboard",
  "businessDescription": "财务数据分析看板：覆盖应收/应付月度趋势、现金流收支、逾期应收预警，以及销售毛利与毛利率的月度拆解。",
  "sqlTemplate": "SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ar_amount, SUM(COALESCE(written_off_amount, 0)) AS ar_written_off_amount, SUM(COALESCE(unwritten_off_amount, 0)) AS ar_unwritten_off_amount FROM fact_ar_receipt WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ORDER BY ym ; SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ap_amount, SUM(COALESCE(written_off_amount, 0)) AS ap_written_off_amount, SUM(COALESCE(unwritten_off_amount, 0)) AS ap_unwritten_off_amount FROM fact_ap_payment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ORDER BY ym ; SELECT DATE(doc_date_utc) AS d, SUM(COALESCE(income_amount, 0)) AS cash_in, SUM(COALESCE(expense_amount, 0)) AS cash_out, SUM(COALESCE(income_amount, 0)) - SUM(COALESCE(expense_amount, 0)) AS net_cash FROM fact_cash_flow WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '60 days' GROUP BY DATE(doc_date_utc) ORDER BY d ; SELECT r.customer_id, c.customer_name, SUM(COALESCE(r.unwritten_off_amount, 0)) AS ar_overdue_balance, MIN(DATE(r.doc_date_utc)) AS oldest_doc_date FROM fact_ar_receipt r LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE WHERE COALESCE(r.unwritten_off_amount, 0) > 0 AND (CURRENT_DATE - DATE(r.doc_date_utc)) > 60 GROUP BY r.customer_id, c.customer_name ORDER BY ar_overdue_balance DESC ; WITH revenue AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ), cost AS ( SELECT to_char(event_time_utc, 'YYYY-MM') AS ym, SUM(COALESCE(ABS(movement_qty) * unit_price, 0)) AS cost_amount FROM fact_inventory_movement WHERE sales_order_id IS NOT NULL AND COALESCE(movement_qty, 0) < 0 AND event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(event_time_utc, 'YYYY-MM') ) SELECT r.ym, r.ship_amount, c.cost_amount, (r.ship_amount - COALESCE(c.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.ship_amount > 0 THEN (r.ship_amount - COALESCE(c.cost_amount, 0)) / r.ship_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost c ON c.ym = r.ym ORDER BY r.ym ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:32:12 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:32:12 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:32:12 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:32:16 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:32:16 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SmartCostPredictionModel
2026-01-09 19:32:16 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:32:16 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:32:16 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SmartCostPredictionModel",
  "businessDescription": "智能成本预测模型：基于历史入库单价估算原材料基准成本，结合BOM用量拆解标准成本结构，并支持原材涨跌价情景推演。",
  "sqlTemplate": "WITH raw_in AS ( SELECT m.product_id, SUM(COALESCE(m.movement_qty, 0)) AS in_qty, SUM(COALESCE(m.movement_qty, 0) * COALESCE(m.unit_price, 0)) AS in_amount FROM fact_inventory_movement m WHERE m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND COALESCE(m.movement_qty, 0) > 0 AND COALESCE(m.unit_price, 0) > 0 GROUP BY m.product_id ) SELECT p.product_code, p.product_name, CASE WHEN ri.in_qty > 0 THEN ri.in_amount / ri.in_qty ELSE NULL END AS base_unit_cost FROM dim_product p LEFT JOIN raw_in ri ON ri.product_id = p.product_id WHERE p.is_current = TRUE AND p.product_type = '标准产品' ; WITH bom_min_level AS ( SELECT bom_number, MIN(COALESCE(level_number, 0)) AS min_level FROM dim_bom WHERE is_current = TRUE GROUP BY bom_number ), parent AS ( SELECT b.bom_number, b.product_code AS parent_product_code FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) = ml.min_level WHERE b.is_current = TRUE ), component AS ( SELECT b.bom_number, b.product_code AS component_product_code, COALESCE(b.unit_usage_qty, 0) AS unit_usage_qty FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) > ml.min_level WHERE b.is_current = TRUE ) SELECT p.bom_number, p.parent_product_code, c.component_product_code, c.unit_usage_qty FROM parent p JOIN component c ON c.bom_number = p.bom_number ORDER BY p.parent_product_code, c.component_product_code ; WITH raw_price AS ( SELECT p.product_code, CASE WHEN SUM(COALESCE(m.movement_qty, 0)) > 0 THEN SUM(COALESCE(m.movement_qty, 0) * COALESCE(m.unit_price, 0)) / SUM(COALESCE(m.movement_qty, 0)) ELSE NULL END AS base_unit_cost FROM dim_product p LEFT JOIN fact_inventory_movement m ON m.product_id = p.product_id AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND COALESCE(m.movement_qty, 0) > 0 AND COALESCE(m.unit_price, 0) > 0 WHERE p.is_current = TRUE AND p.product_type = '标准产品' GROUP BY p.product_code ), bom_min_level AS ( SELECT bom_number, MIN(COALESCE(level_number, 0)) AS min_level FROM dim_bom WHERE is_current = TRUE GROUP BY bom_number ), parent AS ( SELECT b.bom_number, b.product_code AS parent_product_code FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) = ml.min_level WHERE b.is_current = TRUE ), component AS ( SELECT b.bom_number, b.product_code AS component_product_code, COALESCE(b.unit_usage_qty, 0) AS unit_usage_qty FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) > ml.min_level WHERE b.is_current = TRUE ), line_cost AS ( SELECT p.parent_product_code, c.component_product_code, c.unit_usage_qty, rp.base_unit_cost, (c.unit_usage_qty * rp.base_unit_cost) AS component_cost FROM parent p JOIN component c ON c.bom_number = p.bom_number LEFT JOIN raw_price rp ON rp.product_code = c.component_product_code ), total_cost AS ( SELECT parent_product_code, SUM(COALESCE(component_cost, 0)) AS standard_cost FROM line_cost GROUP BY parent_product_code ) SELECT lc.parent_product_code, lc.component_product_code, lc.unit_usage_qty, lc.base_unit_cost, lc.component_cost, tc.standard_cost, CASE WHEN tc.standard_cost > 0 THEN lc.component_cost / tc.standard_cost ELSE NULL END AS cost_share FROM line_cost lc JOIN total_cost tc ON tc.parent_product_code = lc.parent_product_code ORDER BY lc.parent_product_code, cost_share DESC ; WITH scenario AS ( SELECT 'RAW-001' AS material_product_code, 0.10 AS delta_pct ), raw_price AS ( SELECT p.product_code, CASE WHEN SUM(COALESCE(m.movement_qty, 0)) > 0 THEN SUM(COALESCE(m.movement_qty, 0) * COALESCE(m.unit_price, 0)) / SUM(COALESCE(m.movement_qty, 0)) ELSE NULL END AS base_unit_cost FROM dim_product p LEFT JOIN fact_inventory_movement m ON m.product_id = p.product_id AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND COALESCE(m.movement_qty, 0) > 0 AND COALESCE(m.unit_price, 0) > 0 WHERE p.is_current = TRUE AND p.product_type = '标准产品' GROUP BY p.product_code ), bom_min_level AS ( SELECT bom_number, MIN(COALESCE(level_number, 0)) AS min_level FROM dim_bom WHERE is_current = TRUE GROUP BY bom_number ), parent AS ( SELECT b.bom_number, b.product_code AS parent_product_code FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) = ml.min_level WHERE b.is_current = TRUE ), component AS ( SELECT b.bom_number, b.product_code AS component_product_code, COALESCE(b.unit_usage_qty, 0) AS unit_usage_qty FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) > ml.min_level WHERE b.is_current = TRUE ), line_cost AS ( SELECT p.parent_product_code, c.component_product_code, c.unit_usage_qty, rp.base_unit_cost, (c.unit_usage_qty * rp.base_unit_cost) AS component_cost FROM parent p JOIN component c ON c.bom_number = p.bom_number LEFT JOIN raw_price rp ON rp.product_code = c.component_product_code ), total_cost AS ( SELECT parent_product_code, SUM(COALESCE(component_cost, 0)) AS standard_cost FROM line_cost GROUP BY parent_product_code ), delta_cost AS ( SELECT lc.parent_product_code, SUM( CASE WHEN lc.component_product_code = s.material_product_code THEN COALESCE(lc.component_cost, 0) * s.delta_pct ELSE 0 END ) AS scenario_cost_delta FROM line_cost lc CROSS JOIN scenario s GROUP BY lc.parent_product_code ) SELECT tc.parent_product_code, tc.standard_cost AS base_standard_cost, dc.scenario_cost_delta, (tc.standard_cost + COALESCE(dc.scenario_cost_delta, 0)) AS new_standard_cost FROM total_cost tc LEFT JOIN delta_cost dc ON dc.parent_product_code = tc.parent_product_code ORDER BY dc.scenario_cost_delta DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:32:16 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:32:16 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:32:16 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:32:33 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:32:33 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesBIIntelligentAnalyticsPlatform
2026-01-09 19:32:33 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:32:33 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:32:33 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesBIIntelligentAnalyticsPlatform",
  "businessDescription": "销售BI智能分析平台：面向订单、发货/退货、客户复购与毛利贡献等核心指标，提供多维汇总、趋势分析与TOP客户洞察。",
  "sqlTemplate": "SELECT DATE(so.order_date_utc) AS order_date, so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name AS sales_person_name, COUNT(DISTINCT so.sales_order_id) AS order_count, SUM(COALESCE(so.deal_amount, 0)) AS order_amount FROM fact_sales_order so LEFT JOIN dim_customer c ON c.customer_id = so.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = so.sales_person_id AND p.is_current = TRUE GROUP BY DATE(so.order_date_utc), so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name ; WITH ship AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), ret AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS return_amount FROM fact_sales_return WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), keys AS ( SELECT ym, customer_id, sales_person_id FROM ship UNION SELECT ym, customer_id, sales_person_id FROM ret ) SELECT k.ym, k.customer_id, c.customer_name, k.sales_person_id, p.person_name AS sales_person_name, COALESCE(s.ship_amount, 0) AS ship_amount, COALESCE(r.return_amount, 0) AS return_amount, (COALESCE(s.ship_amount, 0) - COALESCE(r.return_amount, 0)) AS net_amount FROM keys k LEFT JOIN ship s ON s.ym = k.ym AND s.customer_id IS NOT DISTINCT FROM k.customer_id AND s.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN ret r ON r.ym = k.ym AND r.customer_id IS NOT DISTINCT FROM k.customer_id AND r.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN dim_customer c ON c.customer_id = k.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = k.sales_person_id AND p.is_current = TRUE ; WITH orders AS ( SELECT so.sales_person_id, so.customer_id, COUNT(DISTINCT so.sales_order_id) AS order_cnt FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.sales_person_id, so.customer_id ), rate AS ( SELECT sales_person_id, COUNT(DISTINCT customer_id) AS customer_cnt, SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) AS repeat_customer_cnt, CASE WHEN COUNT(DISTINCT customer_id) > 0 THEN SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT customer_id) ELSE NULL END AS repurchase_rate FROM orders GROUP BY sales_person_id ), avg_rate AS ( SELECT AVG(repurchase_rate) AS avg_repurchase_rate FROM rate WHERE repurchase_rate IS NOT NULL ) SELECT r.sales_person_id, p.person_name AS sales_person_name, r.customer_cnt, r.repeat_customer_cnt, r.repurchase_rate, a.avg_repurchase_rate FROM rate r CROSS JOIN avg_rate a LEFT JOIN dim_person p ON p.person_id = r.sales_person_id AND p.is_current = TRUE WHERE r.repurchase_rate IS NOT NULL AND r.repurchase_rate < a.avg_repurchase_rate ORDER BY (a.avg_repurchase_rate - r.repurchase_rate) DESC ; WITH revenue AS ( SELECT so.customer_id, SUM(COALESCE(so.deal_amount, 0)) AS revenue_amount FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ), cost AS ( SELECT so.customer_id, SUM(COALESCE(ABS(m.movement_qty) * m.unit_price, 0)) AS cost_amount FROM fact_inventory_movement m JOIN fact_sales_order so ON so.sales_order_id = m.sales_order_id WHERE m.sales_order_id IS NOT NULL AND COALESCE(m.movement_qty, 0) < 0 AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ) SELECT r.customer_id, c.customer_name, r.revenue_amount, COALESCE(k.cost_amount, 0) AS cost_amount, (r.revenue_amount - COALESCE(k.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.revenue_amount > 0 THEN (r.revenue_amount - COALESCE(k.cost_amount, 0)) / r.revenue_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost k ON k.customer_id = r.customer_id LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE ORDER BY gross_profit_amount DESC LIMIT 10 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:32:34 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:32:34 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:32:34 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:34:32 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:34:32 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesBIIntelligentAnalyticsPlatform
2026-01-09 19:34:32 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:34:32 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:34:32 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesBIIntelligentAnalyticsPlatform",
  "businessDescription": "销售BI智能分析平台：面向订单、发货/退货、客户复购与毛利贡献等核心指标，提供多维汇总、趋势分析与TOP客户洞察。",
  "sqlTemplate": "SELECT DATE(so.order_date_utc) AS order_date, so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name AS sales_person_name, COUNT(DISTINCT so.sales_order_id) AS order_count, SUM(COALESCE(so.deal_amount, 0)) AS order_amount FROM fact_sales_order so LEFT JOIN dim_customer c ON c.customer_id = so.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = so.sales_person_id AND p.is_current = TRUE GROUP BY DATE(so.order_date_utc), so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name ; WITH ship AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), ret AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS return_amount FROM fact_sales_return WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), keys AS ( SELECT ym, customer_id, sales_person_id FROM ship UNION SELECT ym, customer_id, sales_person_id FROM ret ) SELECT k.ym, k.customer_id, c.customer_name, k.sales_person_id, p.person_name AS sales_person_name, COALESCE(s.ship_amount, 0) AS ship_amount, COALESCE(r.return_amount, 0) AS return_amount, (COALESCE(s.ship_amount, 0) - COALESCE(r.return_amount, 0)) AS net_amount FROM keys k LEFT JOIN ship s ON s.ym = k.ym AND s.customer_id IS NOT DISTINCT FROM k.customer_id AND s.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN ret r ON r.ym = k.ym AND r.customer_id IS NOT DISTINCT FROM k.customer_id AND r.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN dim_customer c ON c.customer_id = k.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = k.sales_person_id AND p.is_current = TRUE ; WITH orders AS ( SELECT so.sales_person_id, so.customer_id, COUNT(DISTINCT so.sales_order_id) AS order_cnt FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.sales_person_id, so.customer_id ), rate AS ( SELECT sales_person_id, COUNT(DISTINCT customer_id) AS customer_cnt, SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) AS repeat_customer_cnt, CASE WHEN COUNT(DISTINCT customer_id) > 0 THEN SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT customer_id) ELSE NULL END AS repurchase_rate FROM orders GROUP BY sales_person_id ), avg_rate AS ( SELECT AVG(repurchase_rate) AS avg_repurchase_rate FROM rate WHERE repurchase_rate IS NOT NULL ) SELECT r.sales_person_id, p.person_name AS sales_person_name, r.customer_cnt, r.repeat_customer_cnt, r.repurchase_rate, a.avg_repurchase_rate FROM rate r CROSS JOIN avg_rate a LEFT JOIN dim_person p ON p.person_id = r.sales_person_id AND p.is_current = TRUE WHERE r.repurchase_rate IS NOT NULL AND r.repurchase_rate < a.avg_repurchase_rate ORDER BY (a.avg_repurchase_rate - r.repurchase_rate) DESC ; WITH revenue AS ( SELECT so.customer_id, SUM(COALESCE(so.deal_amount, 0)) AS revenue_amount FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ), cost AS ( SELECT so.customer_id, SUM(COALESCE(ABS(m.movement_qty) * m.unit_price, 0)) AS cost_amount FROM fact_inventory_movement m JOIN fact_sales_order so ON so.sales_order_id = m.sales_order_id WHERE m.sales_order_id IS NOT NULL AND COALESCE(m.movement_qty, 0) < 0 AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ) SELECT r.customer_id, c.customer_name, r.revenue_amount, COALESCE(k.cost_amount, 0) AS cost_amount, (r.revenue_amount - COALESCE(k.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.revenue_amount > 0 THEN (r.revenue_amount - COALESCE(k.cost_amount, 0)) / r.revenue_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost k ON k.customer_id = r.customer_id LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE ORDER BY gross_profit_amount DESC LIMIT 10 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:34:32 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:34:32 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:34:32 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:48:17 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:48:17 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SupplierEvaluationAndSmartReplenishment
2026-01-09 19:48:17 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:48:17 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:48:17 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SupplierEvaluationAndSmartReplenishment",
  "businessDescription": "供应商评估与智能补货：基于物料消耗、交付周期、到货准时率与来料质检结果，输出供应商绩效指标与安全库存/再订货点/建议补货量。",
  "sqlTemplate": "WITH mat_out AS ( SELECT product_id, DATE(event_time_utc) AS d, SUM(CASE WHEN doc_type IN ('OUT','OTHER_OUT') THEN ABS(COALESCE(movement_qty, 0)) ELSE 0 END) AS daily_consume FROM fact_inventory_movement WHERE event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '90 days' GROUP BY product_id, DATE(event_time_utc) ), stats AS ( SELECT product_id, AVG(daily_consume) AS avg_daily_consume, STDDEV_POP(daily_consume) AS std_daily_consume FROM mat_out GROUP BY product_id ) SELECT p.product_code, p.product_name, p.uom_code, s.avg_daily_consume, s.std_daily_consume FROM stats s JOIN dim_product p ON p.product_id = s.product_id AND p.is_current = TRUE WHERE p.product_type = '标准产品' ; WITH lead_time AS ( SELECT po.supplier_id, (DATE(pr.doc_date_utc) - DATE(po.doc_date_utc)) AS lead_days, CASE WHEN po.delivery_date_utc IS NOT NULL AND pr.doc_date_utc IS NOT NULL THEN CASE WHEN DATE(pr.doc_date_utc) <= DATE(po.delivery_date_utc) THEN 1 ELSE 0 END ELSE NULL END AS is_ontime FROM fact_purchase_order po JOIN fact_purchase_receipt pr ON pr.purchase_order_number = po.purchase_order_number WHERE po.doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND pr.doc_date_utc IS NOT NULL ), quality AS ( SELECT supplier_id, SUM(COALESCE(pass_qty, 0)) AS pass_qty, SUM(COALESCE(fail_qty, 0)) AS fail_qty FROM fact_quality_inspection WHERE qc_type = 'INCOMING' AND event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY supplier_id ), agg AS ( SELECT supplier_id, AVG(lead_days) AS avg_lead_days, STDDEV_POP(lead_days) AS std_lead_days, AVG(is_ontime) AS ontime_rate FROM lead_time WHERE lead_days IS NOT NULL AND lead_days >= 0 GROUP BY supplier_id ) SELECT s.supplier_id, s.supplier_name, a.avg_lead_days, a.std_lead_days, a.ontime_rate, CASE WHEN (COALESCE(q.pass_qty, 0) + COALESCE(q.fail_qty, 0)) > 0 THEN COALESCE(q.pass_qty, 0) / (COALESCE(q.pass_qty, 0) + COALESCE(q.fail_qty, 0)) ELSE NULL END AS incoming_pass_rate FROM agg a LEFT JOIN dim_supplier s ON s.supplier_id = a.supplier_id AND s.is_current = TRUE LEFT JOIN quality q ON q.supplier_id = a.supplier_id ORDER BY s.supplier_name ; WITH params AS ( SELECT 1.65::numeric AS z, 7::int AS review_days ), consume_daily AS ( SELECT product_id, DATE(event_time_utc) AS d, SUM(CASE WHEN doc_type IN ('OUT','OTHER_OUT') THEN ABS(COALESCE(movement_qty, 0)) ELSE 0 END) AS daily_consume FROM fact_inventory_movement WHERE event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '90 days' GROUP BY product_id, DATE(event_time_utc) ), consume_stats AS ( SELECT product_id, AVG(daily_consume) AS avg_daily_consume, STDDEV_POP(daily_consume) AS std_daily_consume FROM consume_daily GROUP BY product_id ), lead_time AS ( SELECT pr.supplier_id, AVG((DATE(pr.doc_date_utc) - DATE(po.doc_date_utc))) AS avg_lead_days, STDDEV_POP((DATE(pr.doc_date_utc) - DATE(po.doc_date_utc))) AS std_lead_days FROM fact_purchase_order po JOIN fact_purchase_receipt pr ON pr.purchase_order_number = po.purchase_order_number WHERE po.doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND pr.doc_date_utc IS NOT NULL GROUP BY pr.supplier_id ), latest_onhand_row AS ( SELECT m.product_id, m.warehouse_id, m.onhand_qty_after, ROW_NUMBER() OVER (PARTITION BY m.product_id, m.warehouse_id ORDER BY m.event_time_utc DESC, m.inventory_movement_id DESC) AS rn FROM fact_inventory_movement m WHERE m.product_id IS NOT NULL ), onhand AS ( SELECT product_id, SUM(COALESCE(onhand_qty_after, 0)) AS onhand_qty FROM latest_onhand_row WHERE rn = 1 GROUP BY product_id ), product_supplier AS ( SELECT p.product_id, p.product_code, p.product_name, b.supplier_name FROM dim_product p LEFT JOIN dim_bom b ON b.product_code = p.product_code AND b.is_current = TRUE WHERE p.is_current = TRUE AND p.product_type = '标准产品' ), supplier_id_map AS ( SELECT supplier_id, supplier_name FROM dim_supplier WHERE is_current = TRUE ), merged AS ( SELECT ps.product_id, ps.product_code, ps.product_name, sm.supplier_id, COALESCE(cs.avg_daily_consume, 0) AS avg_daily_consume, COALESCE(cs.std_daily_consume, 0) AS std_daily_consume, COALESCE(lt.avg_lead_days, 0) AS avg_lead_days, COALESCE(lt.std_lead_days, 0) AS std_lead_days, COALESCE(oh.onhand_qty, 0) AS onhand_qty FROM product_supplier ps LEFT JOIN supplier_id_map sm ON sm.supplier_name IS NOT DISTINCT FROM ps.supplier_name LEFT JOIN consume_stats cs ON cs.product_id = ps.product_id LEFT JOIN lead_time lt ON lt.supplier_id = sm.supplier_id LEFT JOIN onhand oh ON oh.product_id = ps.product_id ) SELECT product_code, product_name, onhand_qty, avg_daily_consume, std_daily_consume, avg_lead_days, (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) AS safety_stock_qty, (avg_daily_consume * (avg_lead_days + params.review_days)) + (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) AS reorder_point_qty, GREATEST( 0, (avg_daily_consume * (avg_lead_days + params.review_days)) + (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) - onhand_qty ) AS suggest_order_qty, supplier_id FROM merged CROSS JOIN params ORDER BY suggest_order_qty DESC, product_code ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:48:17 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:48:17 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:48:17 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 19:57:13 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 19:57:13 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesPerformanceIntelligentStatistics
2026-01-09 19:57:13 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 19:57:13 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 19:57:13 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesPerformanceIntelligentStatistics",
  "businessDescription": "销售业绩智能统计系统：基于订单成交与合同归属，计算首触/跟进/协同的贡献度分摊，并据此估算推荐佣金与人员贡献排名。",
  "sqlTemplate": "WITH deal AS ( SELECT so.sales_order_id AS deal_id, so.contract_id, so.customer_id, so.sales_person_id, so.deal_amount, so.order_date_utc AS deal_time_utc FROM fact_sales_order so ), role_first AS ( SELECT d.deal_id, COALESCE(dc.owner_id, d.sales_person_id) AS person_id, 'FIRST_TOUCH' AS role, 0.30 AS role_weight FROM deal d LEFT JOIN dim_contract dc ON dc.contract_id = d.contract_id AND dc.is_current = TRUE ), role_follow AS ( SELECT d.deal_id, d.sales_person_id AS person_id, 'FOLLOW_UP' AS role, 0.50 AS role_weight FROM deal d ), collab_people AS ( SELECT DISTINCT s.contract_id, s.operator_id AS person_id FROM fact_sales_shipment s WHERE s.operator_id IS NOT NULL UNION DISTINCT SELECT DISTINCT i.contract_id, i.handler_id AS person_id FROM fact_invoice i WHERE i.handler_id IS NOT NULL UNION DISTINCT SELECT DISTINCT w.contract_id, w.handler_id AS person_id FROM fact_write_off w WHERE w.handler_id IS NOT NULL ), role_collab AS ( SELECT d.deal_id, cp.person_id, 'COLLAB' AS role, 0.20 AS role_weight FROM deal d JOIN collab_people cp ON cp.contract_id = d.contract_id ), roles_union AS ( SELECT * FROM role_first UNION ALL SELECT * FROM role_follow UNION ALL SELECT * FROM role_collab ), collab_cnt AS ( SELECT deal_id, COUNT(DISTINCT person_id) AS collab_person_cnt FROM role_collab GROUP BY deal_id ), normalized AS ( SELECT ru.deal_id, ru.person_id, ru.role, CASE WHEN ru.role = 'COLLAB' THEN ru.role_weight / NULLIF(cc.collab_person_cnt, 0) ELSE ru.role_weight END AS contribution_pct FROM roles_union ru LEFT JOIN collab_cnt cc ON cc.deal_id = ru.deal_id ) SELECT n.deal_id, n.person_id, n.role, n.contribution_pct FROM normalized n ; WITH deal AS ( SELECT so.sales_order_id AS deal_id, so.contract_id, so.customer_id, so.deal_amount, so.order_date_utc AS deal_time_utc FROM fact_sales_order so ), contrib AS ( WITH role_first AS ( SELECT d.deal_id, COALESCE(dc.owner_id, so.sales_person_id) AS person_id, 'FIRST_TOUCH' AS role, 0.30 AS role_weight FROM deal d JOIN fact_sales_order so ON so.sales_order_id = d.deal_id LEFT JOIN dim_contract dc ON dc.contract_id = d.contract_id AND dc.is_current = TRUE ), role_follow AS ( SELECT d.deal_id, so.sales_person_id AS person_id, 'FOLLOW_UP' AS role, 0.50 AS role_weight FROM deal d JOIN fact_sales_order so ON so.sales_order_id = d.deal_id ), collab_people AS ( SELECT DISTINCT s.contract_id, s.operator_id AS person_id FROM fact_sales_shipment s WHERE s.operator_id IS NOT NULL UNION DISTINCT SELECT DISTINCT i.contract_id, i.handler_id AS person_id FROM fact_invoice i WHERE i.handler_id IS NOT NULL UNION DISTINCT SELECT DISTINCT w.contract_id, w.handler_id AS person_id FROM fact_write_off w WHERE w.handler_id IS NOT NULL ), role_collab AS ( SELECT d.deal_id, cp.person_id, 'COLLAB' AS role, 0.20 AS role_weight FROM deal d JOIN collab_people cp ON cp.contract_id = d.contract_id ), roles_union AS ( SELECT * FROM role_first UNION ALL SELECT * FROM role_follow UNION ALL SELECT * FROM role_collab ), collab_cnt AS ( SELECT deal_id, COUNT(DISTINCT person_id) AS collab_person_cnt FROM role_collab GROUP BY deal_id ) SELECT ru.deal_id, ru.person_id, ru.role, CASE WHEN ru.role = 'COLLAB' THEN ru.role_weight / NULLIF(cc.collab_person_cnt, 0) ELSE ru.role_weight END AS contribution_pct FROM roles_union ru LEFT JOIN collab_cnt cc ON cc.deal_id = ru.deal_id ) SELECT d.deal_id, d.deal_time_utc, d.contract_id, d.customer_id, c.customer_name, co.person_id, p.person_name, co.role, co.contribution_pct, d.deal_amount, (d.deal_amount * 0.05 * co.contribution_pct) AS recommend_commission_amount FROM deal d JOIN contrib co ON co.deal_id = d.deal_id LEFT JOIN dim_customer c ON c.customer_id = d.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = co.person_id AND p.is_current = TRUE ORDER BY d.deal_time_utc DESC, d.deal_id, co.contribution_pct DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 19:57:14 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 19:57:14 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 19:57:14 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 20:02:14 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 20:02:14 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: FinancialAnalyticsDashboard
2026-01-09 20:02:14 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 20:02:14 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 20:02:14 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "FinancialAnalyticsDashboard",
  "businessDescription": "财务数据分析看板：覆盖应收/应付月度趋势、现金流收支、逾期应收预警，以及销售毛利与毛利率的月度拆解。",
  "sqlTemplate": "SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ar_amount, SUM(COALESCE(written_off_amount, 0)) AS ar_written_off_amount, SUM(COALESCE(unwritten_off_amount, 0)) AS ar_unwritten_off_amount FROM fact_ar_receipt WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ORDER BY ym ; SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ap_amount, SUM(COALESCE(written_off_amount, 0)) AS ap_written_off_amount, SUM(COALESCE(unwritten_off_amount, 0)) AS ap_unwritten_off_amount FROM fact_ap_payment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ORDER BY ym ; SELECT DATE(doc_date_utc) AS d, SUM(COALESCE(income_amount, 0)) AS cash_in, SUM(COALESCE(expense_amount, 0)) AS cash_out, SUM(COALESCE(income_amount, 0)) - SUM(COALESCE(expense_amount, 0)) AS net_cash FROM fact_cash_flow WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '60 days' GROUP BY DATE(doc_date_utc) ORDER BY d ; SELECT r.customer_id, c.customer_name, SUM(COALESCE(r.unwritten_off_amount, 0)) AS ar_overdue_balance, MIN(DATE(r.doc_date_utc)) AS oldest_doc_date FROM fact_ar_receipt r LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE WHERE COALESCE(r.unwritten_off_amount, 0) > 0 AND (CURRENT_DATE - DATE(r.doc_date_utc)) > 60 GROUP BY r.customer_id, c.customer_name ORDER BY ar_overdue_balance DESC ; WITH revenue AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ), cost AS ( SELECT to_char(event_time_utc, 'YYYY-MM') AS ym, SUM(COALESCE(ABS(movement_qty) * unit_price, 0)) AS cost_amount FROM fact_inventory_movement WHERE sales_order_id IS NOT NULL AND COALESCE(movement_qty, 0) < 0 AND event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(event_time_utc, 'YYYY-MM') ) SELECT r.ym, r.ship_amount, c.cost_amount, (r.ship_amount - COALESCE(c.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.ship_amount > 0 THEN (r.ship_amount - COALESCE(c.cost_amount, 0)) / r.ship_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost c ON c.ym = r.ym ORDER BY r.ym ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 20:02:14 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 20:02:14 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 20:02:14 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 20:06:58 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 20:06:58 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SmartCostPredictionModel
2026-01-09 20:06:58 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 20:06:58 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 20:06:58 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SmartCostPredictionModel",
  "businessDescription": "智能成本预测模型：基于历史入库单价估算原材料基准成本，结合BOM用量拆解标准成本结构，并支持原材涨跌价情景推演。",
  "sqlTemplate": "WITH raw_in AS ( SELECT m.product_id, SUM(COALESCE(m.movement_qty, 0)) AS in_qty, SUM(COALESCE(m.movement_qty, 0) * COALESCE(m.unit_price, 0)) AS in_amount FROM fact_inventory_movement m WHERE m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND COALESCE(m.movement_qty, 0) > 0 AND COALESCE(m.unit_price, 0) > 0 GROUP BY m.product_id ) SELECT p.product_code, p.product_name, CASE WHEN ri.in_qty > 0 THEN ri.in_amount / ri.in_qty ELSE NULL END AS base_unit_cost FROM dim_product p LEFT JOIN raw_in ri ON ri.product_id = p.product_id WHERE p.is_current = TRUE AND p.product_type = '标准产品' ; WITH bom_min_level AS ( SELECT bom_number, MIN(COALESCE(level_number, 0)) AS min_level FROM dim_bom WHERE is_current = TRUE GROUP BY bom_number ), parent AS ( SELECT b.bom_number, b.product_code AS parent_product_code FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) = ml.min_level WHERE b.is_current = TRUE ), component AS ( SELECT b.bom_number, b.product_code AS component_product_code, COALESCE(b.unit_usage_qty, 0) AS unit_usage_qty FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) > ml.min_level WHERE b.is_current = TRUE ) SELECT p.bom_number, p.parent_product_code, c.component_product_code, c.unit_usage_qty FROM parent p JOIN component c ON c.bom_number = p.bom_number ORDER BY p.parent_product_code, c.component_product_code ; WITH raw_price AS ( SELECT p.product_code, CASE WHEN SUM(COALESCE(m.movement_qty, 0)) > 0 THEN SUM(COALESCE(m.movement_qty, 0) * COALESCE(m.unit_price, 0)) / SUM(COALESCE(m.movement_qty, 0)) ELSE NULL END AS base_unit_cost FROM dim_product p LEFT JOIN fact_inventory_movement m ON m.product_id = p.product_id AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND COALESCE(m.movement_qty, 0) > 0 AND COALESCE(m.unit_price, 0) > 0 WHERE p.is_current = TRUE AND p.product_type = '标准产品' GROUP BY p.product_code ), bom_min_level AS ( SELECT bom_number, MIN(COALESCE(level_number, 0)) AS min_level FROM dim_bom WHERE is_current = TRUE GROUP BY bom_number ), parent AS ( SELECT b.bom_number, b.product_code AS parent_product_code FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) = ml.min_level WHERE b.is_current = TRUE ), component AS ( SELECT b.bom_number, b.product_code AS component_product_code, COALESCE(b.unit_usage_qty, 0) AS unit_usage_qty FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) > ml.min_level WHERE b.is_current = TRUE ), line_cost AS ( SELECT p.parent_product_code, c.component_product_code, c.unit_usage_qty, rp.base_unit_cost, (c.unit_usage_qty * rp.base_unit_cost) AS component_cost FROM parent p JOIN component c ON c.bom_number = p.bom_number LEFT JOIN raw_price rp ON rp.product_code = c.component_product_code ), total_cost AS ( SELECT parent_product_code, SUM(COALESCE(component_cost, 0)) AS standard_cost FROM line_cost GROUP BY parent_product_code ) SELECT lc.parent_product_code, lc.component_product_code, lc.unit_usage_qty, lc.base_unit_cost, lc.component_cost, tc.standard_cost, CASE WHEN tc.standard_cost > 0 THEN lc.component_cost / tc.standard_cost ELSE NULL END AS cost_share FROM line_cost lc JOIN total_cost tc ON tc.parent_product_code = lc.parent_product_code ORDER BY lc.parent_product_code, cost_share DESC ; WITH scenario AS ( SELECT 'RAW-001' AS material_product_code, 0.10 AS delta_pct ), raw_price AS ( SELECT p.product_code, CASE WHEN SUM(COALESCE(m.movement_qty, 0)) > 0 THEN SUM(COALESCE(m.movement_qty, 0) * COALESCE(m.unit_price, 0)) / SUM(COALESCE(m.movement_qty, 0)) ELSE NULL END AS base_unit_cost FROM dim_product p LEFT JOIN fact_inventory_movement m ON m.product_id = p.product_id AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND COALESCE(m.movement_qty, 0) > 0 AND COALESCE(m.unit_price, 0) > 0 WHERE p.is_current = TRUE AND p.product_type = '标准产品' GROUP BY p.product_code ), bom_min_level AS ( SELECT bom_number, MIN(COALESCE(level_number, 0)) AS min_level FROM dim_bom WHERE is_current = TRUE GROUP BY bom_number ), parent AS ( SELECT b.bom_number, b.product_code AS parent_product_code FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) = ml.min_level WHERE b.is_current = TRUE ), component AS ( SELECT b.bom_number, b.product_code AS component_product_code, COALESCE(b.unit_usage_qty, 0) AS unit_usage_qty FROM dim_bom b JOIN bom_min_level ml ON ml.bom_number = b.bom_number AND COALESCE(b.level_number, 0) > ml.min_level WHERE b.is_current = TRUE ), line_cost AS ( SELECT p.parent_product_code, c.component_product_code, c.unit_usage_qty, rp.base_unit_cost, (c.unit_usage_qty * rp.base_unit_cost) AS component_cost FROM parent p JOIN component c ON c.bom_number = p.bom_number LEFT JOIN raw_price rp ON rp.product_code = c.component_product_code ), total_cost AS ( SELECT parent_product_code, SUM(COALESCE(component_cost, 0)) AS standard_cost FROM line_cost GROUP BY parent_product_code ), delta_cost AS ( SELECT lc.parent_product_code, SUM( CASE WHEN lc.component_product_code = s.material_product_code THEN COALESCE(lc.component_cost, 0) * s.delta_pct ELSE 0 END ) AS scenario_cost_delta FROM line_cost lc CROSS JOIN scenario s GROUP BY lc.parent_product_code ) SELECT tc.parent_product_code, tc.standard_cost AS base_standard_cost, dc.scenario_cost_delta, (tc.standard_cost + COALESCE(dc.scenario_cost_delta, 0)) AS new_standard_cost FROM total_cost tc LEFT JOIN delta_cost dc ON dc.parent_product_code = tc.parent_product_code ORDER BY dc.scenario_cost_delta DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 20:06:58 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 20:06:58 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 20:06:58 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 20:23:12 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 20:23:12 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: HumanResourcesAnalytics
2026-01-09 20:23:12 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 20:23:12 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 20:23:12 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "HumanResourcesAnalytics",
  "businessDescription": "人力资源数据分析：提供月度在岗人数、招聘/离职趋势、产线部门离职率连续上升预警，以及岗位空缺天数分析。",
  "sqlTemplate": "WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ) SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, p.position, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department, p.position ORDER BY ym, p.department, p.position ; SELECT to_char(employment_day, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS hire_count FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL AND employment_day >= (CURRENT_DATE - INTERVAL '12 months') GROUP BY to_char(employment_day, 'YYYY-MM'), department, position ORDER BY ym, department, position ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ) SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department, position ORDER BY ym, department, position ; WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ), headcount AS ( SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' WHERE p.department LIKE '%产线%' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department ), ordered AS ( SELECT person_id, department, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person WHERE department LIKE '%产线%' ), exit_event AS ( SELECT person_id, department, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), exit_cnt AS ( SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department ), rate AS ( SELECT h.ym, h.department, COALESCE(e.exit_count, 0) AS exit_count, h.headcount_active, CASE WHEN h.headcount_active > 0 THEN COALESCE(e.exit_count, 0) / h.headcount_active ELSE NULL END AS monthly_turnover_rate FROM headcount h LEFT JOIN exit_cnt e ON e.ym = h.ym AND e.department IS NOT DISTINCT FROM h.department ), flag AS ( SELECT r.*, LAG(monthly_turnover_rate, 1) OVER (PARTITION BY department ORDER BY ym) AS r_m1, LAG(monthly_turnover_rate, 2) OVER (PARTITION BY department ORDER BY ym) AS r_m2 FROM rate r ) SELECT ym, department, exit_count, headcount_active, monthly_turnover_rate FROM flag WHERE monthly_turnover_rate IS NOT NULL AND r_m1 IS NOT NULL AND r_m2 IS NOT NULL AND monthly_turnover_rate > r_m1 AND r_m1 > r_m2 ORDER BY department, ym ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), hire_event AS ( SELECT department, position, employment_day AS hire_date, person_id FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL ), matched AS ( SELECT e.department, e.position, e.exit_time, ( SELECT MIN(h.hire_date) FROM hire_event h WHERE h.department IS NOT DISTINCT FROM e.department AND h.position IS NOT DISTINCT FROM e.position AND h.hire_date > DATE(e.exit_time) ) AS next_hire_date FROM exit_event e ) SELECT department, position, DATE(exit_time) AS exit_date, next_hire_date, (next_hire_date - DATE(exit_time)) AS vacancy_days FROM matched WHERE next_hire_date IS NOT NULL ORDER BY vacancy_days DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 20:23:12 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 20:23:12 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 20:23:12 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 20:26:12 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 20:26:12 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: HumanResourcesAnalytics
2026-01-09 20:26:12 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 20:26:12 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 20:26:12 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "HumanResourcesAnalytics",
  "businessDescription": "人力资源数据分析：提供月度在岗人数、招聘/离职趋势、产线部门离职率连续上升预警，以及岗位空缺天数分析。",
  "sqlTemplate": "WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ) SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, p.position, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department, p.position ORDER BY ym, p.department, p.position ; SELECT to_char(employment_day, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS hire_count FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL AND employment_day >= (CURRENT_DATE - INTERVAL '12 months') GROUP BY to_char(employment_day, 'YYYY-MM'), department, position ORDER BY ym, department, position ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ) SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department, position ORDER BY ym, department, position ; WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ), headcount AS ( SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' WHERE p.department LIKE '%产线%' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department ), ordered AS ( SELECT person_id, department, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person WHERE department LIKE '%产线%' ), exit_event AS ( SELECT person_id, department, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), exit_cnt AS ( SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department ), rate AS ( SELECT h.ym, h.department, COALESCE(e.exit_count, 0) AS exit_count, h.headcount_active, CASE WHEN h.headcount_active > 0 THEN COALESCE(e.exit_count, 0) / h.headcount_active ELSE NULL END AS monthly_turnover_rate FROM headcount h LEFT JOIN exit_cnt e ON e.ym = h.ym AND e.department IS NOT DISTINCT FROM h.department ), flag AS ( SELECT r.*, LAG(monthly_turnover_rate, 1) OVER (PARTITION BY department ORDER BY ym) AS r_m1, LAG(monthly_turnover_rate, 2) OVER (PARTITION BY department ORDER BY ym) AS r_m2 FROM rate r ) SELECT ym, department, exit_count, headcount_active, monthly_turnover_rate FROM flag WHERE monthly_turnover_rate IS NOT NULL AND r_m1 IS NOT NULL AND r_m2 IS NOT NULL AND monthly_turnover_rate > r_m1 AND r_m1 > r_m2 ORDER BY department, ym ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), hire_event AS ( SELECT department, position, employment_day AS hire_date, person_id FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL ), matched AS ( SELECT e.department, e.position, e.exit_time, ( SELECT MIN(h.hire_date) FROM hire_event h WHERE h.department IS NOT DISTINCT FROM e.department AND h.position IS NOT DISTINCT FROM e.position AND h.hire_date > DATE(e.exit_time) ) AS next_hire_date FROM exit_event e ) SELECT department, position, DATE(exit_time) AS exit_date, next_hire_date, (next_hire_date - DATE(exit_time)) AS vacancy_days FROM matched WHERE next_hire_date IS NOT NULL ORDER BY vacancy_days DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 20:26:13 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 20:26:13 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 20:26:13 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 20:38:58 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 20:38:58 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: HumanResourcesAnalytics
2026-01-09 20:38:58 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 20:38:58 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 20:38:58 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "HumanResourcesAnalytics",
  "businessDescription": "人力资源数据分析：提供月度在岗人数、招聘/离职趋势、产线部门离职率连续上升预警，以及岗位空缺天数分析。",
  "sqlTemplate": "WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ) SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, p.position, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department, p.position ORDER BY ym, p.department, p.position ; SELECT to_char(employment_day, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS hire_count FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL AND employment_day >= (CURRENT_DATE - INTERVAL '12 months') GROUP BY to_char(employment_day, 'YYYY-MM'), department, position ORDER BY ym, department, position ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ) SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department, position ORDER BY ym, department, position ; WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ), headcount AS ( SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' WHERE p.department LIKE '%产线%' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department ), ordered AS ( SELECT person_id, department, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person WHERE department LIKE '%产线%' ), exit_event AS ( SELECT person_id, department, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), exit_cnt AS ( SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department ), rate AS ( SELECT h.ym, h.department, COALESCE(e.exit_count, 0) AS exit_count, h.headcount_active, CASE WHEN h.headcount_active > 0 THEN COALESCE(e.exit_count, 0) / h.headcount_active ELSE NULL END AS monthly_turnover_rate FROM headcount h LEFT JOIN exit_cnt e ON e.ym = h.ym AND e.department IS NOT DISTINCT FROM h.department ), flag AS ( SELECT r.*, LAG(monthly_turnover_rate, 1) OVER (PARTITION BY department ORDER BY ym) AS r_m1, LAG(monthly_turnover_rate, 2) OVER (PARTITION BY department ORDER BY ym) AS r_m2 FROM rate r ) SELECT ym, department, exit_count, headcount_active, monthly_turnover_rate FROM flag WHERE monthly_turnover_rate IS NOT NULL AND r_m1 IS NOT NULL AND r_m2 IS NOT NULL AND monthly_turnover_rate > r_m1 AND r_m1 > r_m2 ORDER BY department, ym ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), hire_event AS ( SELECT department, position, employment_day AS hire_date, person_id FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL ), matched AS ( SELECT e.department, e.position, e.exit_time, ( SELECT MIN(h.hire_date) FROM hire_event h WHERE h.department IS NOT DISTINCT FROM e.department AND h.position IS NOT DISTINCT FROM e.position AND h.hire_date > DATE(e.exit_time) ) AS next_hire_date FROM exit_event e ) SELECT department, position, DATE(exit_time) AS exit_date, next_hire_date, (next_hire_date - DATE(exit_time)) AS vacancy_days FROM matched WHERE next_hire_date IS NOT NULL ORDER BY vacancy_days DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 20:38:58 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 20:38:58 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 20:38:58 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-09 20:43:32 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\logs
2026-01-09 20:43:32 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:313] - ============================================================
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:316] - ============================================================
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID: 
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:324] - ============================================================
2026-01-09 20:43:32 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动，等待客户端连接...
2026-01-09 20:43:33 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest
2026-01-09 20:43:33 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
2026-01-09 20:43:33 - mcp_services - INFO - [main.py:119] - 初始化查询配置（数据源: local）...
2026-01-09 20:43:33 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
2026-01-09 20:43:33 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
2026-01-09 20:43:33 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
2026-01-09 20:43:35 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-09 20:43:35 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: HumanResourcesAnalytics
2026-01-09 20:43:35 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-09 20:43:35 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-09 20:43:35 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "HumanResourcesAnalytics",
  "businessDescription": "人力资源数据分析：提供月度在岗人数、招聘/离职趋势、产线部门离职率连续上升预警，以及岗位空缺天数分析。",
  "sqlTemplate": "WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ) SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, p.position, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department, p.position ORDER BY ym, p.department, p.position ; SELECT to_char(employment_day, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS hire_count FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL AND employment_day >= (CURRENT_DATE - INTERVAL '12 months') GROUP BY to_char(employment_day, 'YYYY-MM'), department, position ORDER BY ym, department, position ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ) SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department, position ORDER BY ym, department, position ; WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ), headcount AS ( SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department ), ordered AS ( SELECT person_id, department, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), exit_cnt AS ( SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department ), rate AS ( SELECT h.ym, h.department, COALESCE(e.exit_count, 0) AS exit_count, h.headcount_active, CASE WHEN h.headcount_active > 0 THEN COALESCE(e.exit_count, 0) / h.headcount_active ELSE NULL END AS monthly_turnover_rate FROM headcount h LEFT JOIN exit_cnt e ON e.ym = h.ym AND e.department IS NOT DISTINCT FROM h.department ), flag AS ( SELECT r.*, LAG(monthly_turnover_rate, 1) OVER (PARTITION BY department ORDER BY ym) AS r_m1, LAG(monthly_turnover_rate, 2) OVER (PARTITION BY department ORDER BY ym) AS r_m2 FROM rate r ) SELECT ym, department, exit_count, headcount_active, monthly_turnover_rate FROM flag WHERE monthly_turnover_rate IS NOT NULL AND r_m1 IS NOT NULL AND r_m2 IS NOT NULL AND monthly_turnover_rate > r_m1 AND r_m1 > r_m2 ORDER BY department, ym ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), hire_event AS ( SELECT department, position, employment_day AS hire_date, person_id FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL ), matched AS ( SELECT e.department, e.position, e.exit_time, ( SELECT MIN(h.hire_date) FROM hire_event h WHERE h.department IS NOT DISTINCT FROM e.department AND h.position IS NOT DISTINCT FROM e.position AND h.hire_date > DATE(e.exit_time) ) AS next_hire_date FROM exit_event e ) SELECT department, position, DATE(exit_time) AS exit_date, next_hire_date, (next_hire_date - DATE(exit_time)) AS vacancy_days FROM matched WHERE next_hire_date IS NOT NULL ORDER BY vacancy_days DESC ;",
  "parameters": {},
  "testParams": {}
}
2026-01-09 20:43:35 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-09 20:43:35 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-09 20:43:35 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-16 12:40:03 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\logs
2026-01-16 12:40:03 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:313] - ============================================================
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:316] - ============================================================
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID: 
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:324] - ============================================================
2026-01-16 12:40:03 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动，等待客户端连接...
2026-01-16 12:40:04 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest
2026-01-16 12:40:04 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
2026-01-16 12:40:04 - mcp_services - INFO - [main.py:119] - 初始化查询配置（数据源: local）...
2026-01-16 12:40:04 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
2026-01-16 12:40:04 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
2026-01-16 12:40:04 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
2026-01-16 12:40:05 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-16 12:40:05 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SupplierEvaluationAndSmartReplenishment
2026-01-16 12:40:05 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-16 12:40:05 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-16 12:40:05 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SupplierEvaluationAndSmartReplenishment",
  "businessDescription": "供应商评估与智能补货：基于物料消耗、交付周期、到货准时率与来料质检结果，输出供应商绩效指标与安全库存/再订货点/建议补货量。",
  "sqlTemplate": "WITH mat_out AS ( SELECT product_id, DATE(event_time_utc) AS d, SUM(CASE WHEN doc_type IN ('OUT','OTHER_OUT') THEN ABS(COALESCE(movement_qty, 0)) ELSE 0 END) AS daily_consume FROM fact_inventory_movement WHERE event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '90 days' GROUP BY product_id, DATE(event_time_utc) ), stats AS ( SELECT product_id, AVG(daily_consume) AS avg_daily_consume, STDDEV_POP(daily_consume) AS std_daily_consume FROM mat_out GROUP BY product_id ) SELECT p.product_code, p.product_name, p.uom_code, s.avg_daily_consume, s.std_daily_consume FROM stats s JOIN dim_product p ON p.product_id = s.product_id AND p.is_current = TRUE WHERE p.product_type = '标准产品' ; WITH lead_time AS ( SELECT po.supplier_id, (DATE(pr.doc_date_utc) - DATE(po.doc_date_utc)) AS lead_days, CASE WHEN po.delivery_date_utc IS NOT NULL AND pr.doc_date_utc IS NOT NULL THEN CASE WHEN DATE(pr.doc_date_utc) <= DATE(po.delivery_date_utc) THEN 1 ELSE 0 END ELSE NULL END AS is_ontime FROM fact_purchase_order po JOIN fact_purchase_receipt pr ON pr.purchase_order_number = po.purchase_order_number WHERE po.doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND pr.doc_date_utc IS NOT NULL ), quality AS ( SELECT supplier_id, SUM(COALESCE(pass_qty, 0)) AS pass_qty, SUM(COALESCE(fail_qty, 0)) AS fail_qty FROM fact_quality_inspection WHERE qc_type = 'INCOMING' AND event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY supplier_id ), agg AS ( SELECT supplier_id, AVG(lead_days) AS avg_lead_days, STDDEV_POP(lead_days) AS std_lead_days, AVG(is_ontime) AS ontime_rate FROM lead_time WHERE lead_days IS NOT NULL AND lead_days >= 0 GROUP BY supplier_id ) SELECT s.supplier_id, s.supplier_name, a.avg_lead_days, a.std_lead_days, a.ontime_rate, CASE WHEN (COALESCE(q.pass_qty, 0) + COALESCE(q.fail_qty, 0)) > 0 THEN COALESCE(q.pass_qty, 0) / (COALESCE(q.pass_qty, 0) + COALESCE(q.fail_qty, 0)) ELSE NULL END AS incoming_pass_rate FROM agg a LEFT JOIN dim_supplier s ON s.supplier_id = a.supplier_id AND s.is_current = TRUE LEFT JOIN quality q ON q.supplier_id = a.supplier_id ORDER BY s.supplier_name LIMIT 30 ; WITH params AS ( SELECT 1.65::numeric AS z, 7::int AS review_days ), consume_daily AS ( SELECT product_id, DATE(event_time_utc) AS d, SUM(CASE WHEN doc_type IN ('OUT','OTHER_OUT') THEN ABS(COALESCE(movement_qty, 0)) ELSE 0 END) AS daily_consume FROM fact_inventory_movement WHERE event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '90 days' GROUP BY product_id, DATE(event_time_utc) ), consume_stats AS ( SELECT product_id, AVG(daily_consume) AS avg_daily_consume, STDDEV_POP(daily_consume) AS std_daily_consume FROM consume_daily GROUP BY product_id ), lead_time AS ( SELECT pr.supplier_id, AVG((DATE(pr.doc_date_utc) - DATE(po.doc_date_utc))) AS avg_lead_days, STDDEV_POP((DATE(pr.doc_date_utc) - DATE(po.doc_date_utc))) AS std_lead_days FROM fact_purchase_order po JOIN fact_purchase_receipt pr ON pr.purchase_order_number = po.purchase_order_number WHERE po.doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' AND pr.doc_date_utc IS NOT NULL GROUP BY pr.supplier_id ), latest_onhand_row AS ( SELECT m.product_id, m.warehouse_id, m.onhand_qty_after, ROW_NUMBER() OVER (PARTITION BY m.product_id, m.warehouse_id ORDER BY m.event_time_utc DESC, m.inventory_movement_id DESC) AS rn FROM fact_inventory_movement m WHERE m.product_id IS NOT NULL ), onhand AS ( SELECT product_id, SUM(COALESCE(onhand_qty_after, 0)) AS onhand_qty FROM latest_onhand_row WHERE rn = 1 GROUP BY product_id ), product_supplier AS ( SELECT p.product_id, p.product_code, p.product_name, b.supplier_name FROM dim_product p LEFT JOIN dim_bom b ON b.product_code = p.product_code AND b.is_current = TRUE WHERE p.is_current = TRUE AND p.product_type = '标准产品' ), supplier_id_map AS ( SELECT supplier_id, supplier_name FROM dim_supplier WHERE is_current = TRUE ), merged AS ( SELECT ps.product_id, ps.product_code, ps.product_name, sm.supplier_id, COALESCE(cs.avg_daily_consume, 0) AS avg_daily_consume, COALESCE(cs.std_daily_consume, 0) AS std_daily_consume, COALESCE(lt.avg_lead_days, 0) AS avg_lead_days, COALESCE(lt.std_lead_days, 0) AS std_lead_days, COALESCE(oh.onhand_qty, 0) AS onhand_qty FROM product_supplier ps LEFT JOIN supplier_id_map sm ON sm.supplier_name IS NOT DISTINCT FROM ps.supplier_name LEFT JOIN consume_stats cs ON cs.product_id = ps.product_id LEFT JOIN lead_time lt ON lt.supplier_id = sm.supplier_id LEFT JOIN onhand oh ON oh.product_id = ps.product_id ) SELECT product_code, product_name, onhand_qty, avg_daily_consume, std_daily_consume, avg_lead_days, (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) AS safety_stock_qty, (avg_daily_consume * (avg_lead_days + params.review_days)) + (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) AS reorder_point_qty, GREATEST( 0, (avg_daily_consume * (avg_lead_days + params.review_days)) + (params.z * std_daily_consume * SQRT(GREATEST(avg_lead_days, 0))) - onhand_qty ) AS suggest_order_qty, supplier_id FROM merged CROSS JOIN params ORDER BY suggest_order_qty DESC, product_code LIMIT 30 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-16 12:40:05 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-16 12:40:05 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-16 12:40:05 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-16 12:40:06 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-16 12:40:06 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesBIIntelligentAnalyticsPlatform
2026-01-16 12:40:06 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-16 12:40:06 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-16 12:40:06 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesBIIntelligentAnalyticsPlatform",
  "businessDescription": "销售BI智能分析平台：面向订单、发货/退货、客户复购与毛利贡献等核心指标，提供多维汇总、趋势分析与TOP客户洞察。",
  "sqlTemplate": "SELECT DATE(so.order_date_utc) AS order_date, so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name AS sales_person_name, COUNT(DISTINCT so.sales_order_id) AS order_count, SUM(COALESCE(so.deal_amount, 0)) AS order_amount FROM fact_sales_order so LEFT JOIN dim_customer c ON c.customer_id = so.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = so.sales_person_id AND p.is_current = TRUE GROUP BY DATE(so.order_date_utc), so.customer_id, c.customer_name, c.customer_level, c.industry, c.address, so.sales_person_id, p.person_name LIMIT 30 ; WITH ship AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), ret AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, customer_id, sales_person_id, SUM(COALESCE(amount, 0)) AS return_amount FROM fact_sales_return WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM'), customer_id, sales_person_id ), keys AS ( SELECT ym, customer_id, sales_person_id FROM ship UNION SELECT ym, customer_id, sales_person_id FROM ret ) SELECT k.ym, k.customer_id, c.customer_name, k.sales_person_id, p.person_name AS sales_person_name, COALESCE(s.ship_amount, 0) AS ship_amount, COALESCE(r.return_amount, 0) AS return_amount, (COALESCE(s.ship_amount, 0) - COALESCE(r.return_amount, 0)) AS net_amount FROM keys k LEFT JOIN ship s ON s.ym = k.ym AND s.customer_id IS NOT DISTINCT FROM k.customer_id AND s.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN ret r ON r.ym = k.ym AND r.customer_id IS NOT DISTINCT FROM k.customer_id AND r.sales_person_id IS NOT DISTINCT FROM k.sales_person_id LEFT JOIN dim_customer c ON c.customer_id = k.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = k.sales_person_id AND p.is_current = TRUE LIMIT 30 ; WITH orders AS ( SELECT so.sales_person_id, so.customer_id, COUNT(DISTINCT so.sales_order_id) AS order_cnt FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.sales_person_id, so.customer_id ), rate AS ( SELECT sales_person_id, COUNT(DISTINCT customer_id) AS customer_cnt, SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) AS repeat_customer_cnt, CASE WHEN COUNT(DISTINCT customer_id) > 0 THEN SUM(CASE WHEN order_cnt >= 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT customer_id) ELSE NULL END AS repurchase_rate FROM orders GROUP BY sales_person_id ), avg_rate AS ( SELECT AVG(repurchase_rate) AS avg_repurchase_rate FROM rate WHERE repurchase_rate IS NOT NULL ) SELECT r.sales_person_id, p.person_name AS sales_person_name, r.customer_cnt, r.repeat_customer_cnt, r.repurchase_rate, a.avg_repurchase_rate FROM rate r CROSS JOIN avg_rate a LEFT JOIN dim_person p ON p.person_id = r.sales_person_id AND p.is_current = TRUE WHERE r.repurchase_rate IS NOT NULL AND r.repurchase_rate < a.avg_repurchase_rate ORDER BY (a.avg_repurchase_rate - r.repurchase_rate) DESC LIMIT 30 ; WITH revenue AS ( SELECT so.customer_id, SUM(COALESCE(so.deal_amount, 0)) AS revenue_amount FROM fact_sales_order so WHERE so.order_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ), cost AS ( SELECT so.customer_id, SUM(COALESCE(ABS(m.movement_qty) * m.unit_price, 0)) AS cost_amount FROM fact_inventory_movement m JOIN fact_sales_order so ON so.sales_order_id = m.sales_order_id WHERE m.sales_order_id IS NOT NULL AND COALESCE(m.movement_qty, 0) < 0 AND m.event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '180 days' GROUP BY so.customer_id ) SELECT r.customer_id, c.customer_name, r.revenue_amount, COALESCE(k.cost_amount, 0) AS cost_amount, (r.revenue_amount - COALESCE(k.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.revenue_amount > 0 THEN (r.revenue_amount - COALESCE(k.cost_amount, 0)) / r.revenue_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost k ON k.customer_id = r.customer_id LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE ORDER BY gross_profit_amount DESC LIMIT 10 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-16 12:40:06 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-16 12:40:06 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-16 12:40:06 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-16 12:40:07 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-16 12:40:07 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesPerformanceIntelligentStatistics
2026-01-16 12:40:07 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-16 12:40:07 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-16 12:40:07 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "SalesPerformanceIntelligentStatistics",
  "businessDescription": "销售业绩智能统计系统：基于订单成交与合同归属，计算首触/跟进/协同的贡献度分摊，并据此估算推荐佣金与人员贡献排名。",
  "sqlTemplate": "WITH deal AS ( SELECT so.sales_order_id AS deal_id, so.contract_id, so.customer_id, so.sales_person_id, so.deal_amount, so.order_date_utc AS deal_time_utc FROM fact_sales_order so ), role_first AS ( SELECT d.deal_id, COALESCE(dc.owner_id, d.sales_person_id) AS person_id, 'FIRST_TOUCH' AS role, 0.30 AS role_weight FROM deal d LEFT JOIN dim_contract dc ON dc.contract_id = d.contract_id AND dc.is_current = TRUE ), role_follow AS ( SELECT d.deal_id, d.sales_person_id AS person_id, 'FOLLOW_UP' AS role, 0.50 AS role_weight FROM deal d ), collab_people AS ( SELECT DISTINCT s.contract_id, s.operator_id AS person_id FROM fact_sales_shipment s WHERE s.operator_id IS NOT NULL UNION DISTINCT SELECT DISTINCT i.contract_id, i.handler_id AS person_id FROM fact_invoice i WHERE i.handler_id IS NOT NULL UNION DISTINCT SELECT DISTINCT w.contract_id, w.handler_id AS person_id FROM fact_write_off w WHERE w.handler_id IS NOT NULL ), role_collab AS ( SELECT d.deal_id, cp.person_id, 'COLLAB' AS role, 0.20 AS role_weight FROM deal d JOIN collab_people cp ON cp.contract_id = d.contract_id ), roles_union AS ( SELECT * FROM role_first UNION ALL SELECT * FROM role_follow UNION ALL SELECT * FROM role_collab ), collab_cnt AS ( SELECT deal_id, COUNT(DISTINCT person_id) AS collab_person_cnt FROM role_collab GROUP BY deal_id ), normalized AS ( SELECT ru.deal_id, ru.person_id, ru.role, CASE WHEN ru.role = 'COLLAB' THEN ru.role_weight / NULLIF(cc.collab_person_cnt, 0) ELSE ru.role_weight END AS contribution_pct FROM roles_union ru LEFT JOIN collab_cnt cc ON cc.deal_id = ru.deal_id ) SELECT n.deal_id, n.person_id, n.role, n.contribution_pct FROM normalized n LIMIT 30 ; WITH deal AS ( SELECT so.sales_order_id AS deal_id, so.contract_id, so.customer_id, so.deal_amount, so.order_date_utc AS deal_time_utc FROM fact_sales_order so ), contrib AS ( WITH role_first AS ( SELECT d.deal_id, COALESCE(dc.owner_id, so.sales_person_id) AS person_id, 'FIRST_TOUCH' AS role, 0.30 AS role_weight FROM deal d JOIN fact_sales_order so ON so.sales_order_id = d.deal_id LEFT JOIN dim_contract dc ON dc.contract_id = d.contract_id AND dc.is_current = TRUE ), role_follow AS ( SELECT d.deal_id, so.sales_person_id AS person_id, 'FOLLOW_UP' AS role, 0.50 AS role_weight FROM deal d JOIN fact_sales_order so ON so.sales_order_id = d.deal_id ), collab_people AS ( SELECT DISTINCT s.contract_id, s.operator_id AS person_id FROM fact_sales_shipment s WHERE s.operator_id IS NOT NULL UNION DISTINCT SELECT DISTINCT i.contract_id, i.handler_id AS person_id FROM fact_invoice i WHERE i.handler_id IS NOT NULL UNION DISTINCT SELECT DISTINCT w.contract_id, w.handler_id AS person_id FROM fact_write_off w WHERE w.handler_id IS NOT NULL ), role_collab AS ( SELECT d.deal_id, cp.person_id, 'COLLAB' AS role, 0.20 AS role_weight FROM deal d JOIN collab_people cp ON cp.contract_id = d.contract_id ), roles_union AS ( SELECT * FROM role_first UNION ALL SELECT * FROM role_follow UNION ALL SELECT * FROM role_collab ), collab_cnt AS ( SELECT deal_id, COUNT(DISTINCT person_id) AS collab_person_cnt FROM role_collab GROUP BY deal_id ) SELECT ru.deal_id, ru.person_id, ru.role, CASE WHEN ru.role = 'COLLAB' THEN ru.role_weight / NULLIF(cc.collab_person_cnt, 0) ELSE ru.role_weight END AS contribution_pct FROM roles_union ru LEFT JOIN collab_cnt cc ON cc.deal_id = ru.deal_id ) SELECT d.deal_id, d.deal_time_utc, d.contract_id, d.customer_id, c.customer_name, co.person_id, p.person_name, co.role, co.contribution_pct, d.deal_amount, (d.deal_amount * 0.05 * co.contribution_pct) AS recommend_commission_amount FROM deal d JOIN contrib co ON co.deal_id = d.deal_id LEFT JOIN dim_customer c ON c.customer_id = d.customer_id AND c.is_current = TRUE LEFT JOIN dim_person p ON p.person_id = co.person_id AND p.is_current = TRUE ORDER BY d.deal_time_utc DESC, d.deal_id, co.contribution_pct DESC LIMIT 30 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-16 12:40:07 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-16 12:40:07 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-16 12:40:07 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-16 12:40:08 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-16 12:40:08 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: FinancialAnalyticsDashboard
2026-01-16 12:40:08 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-16 12:40:08 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-16 12:40:08 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "FinancialAnalyticsDashboard",
  "businessDescription": "财务数据分析看板：覆盖应收/应付月度趋势、现金流收支、逾期应收预警，以及销售毛利与毛利率的月度拆解。",
  "sqlTemplate": "SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ar_amount, SUM(COALESCE(written_off_amount, 0)) AS ar_written_off_amount, SUM(COALESCE(unwritten_off_amount, 0)) AS ar_unwritten_off_amount FROM fact_ar_receipt WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ORDER BY ym ; SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ap_amount, SUM(COALESCE(written_off_amount, 0)) AS ap_written_off_amount, SUM(COALESCE(unwritten_off_amount, 0)) AS ap_unwritten_off_amount FROM fact_ap_payment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ORDER BY ym ; SELECT DATE(doc_date_utc) AS d, SUM(COALESCE(income_amount, 0)) AS cash_in, SUM(COALESCE(expense_amount, 0)) AS cash_out, SUM(COALESCE(income_amount, 0)) - SUM(COALESCE(expense_amount, 0)) AS net_cash FROM fact_cash_flow WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '60 days' GROUP BY DATE(doc_date_utc) ORDER BY d LIMIT 30 ; SELECT r.customer_id, c.customer_name, SUM(COALESCE(r.unwritten_off_amount, 0)) AS ar_overdue_balance, MIN(DATE(r.doc_date_utc)) AS oldest_doc_date FROM fact_ar_receipt r LEFT JOIN dim_customer c ON c.customer_id = r.customer_id AND c.is_current = TRUE WHERE COALESCE(r.unwritten_off_amount, 0) > 0 AND (CURRENT_DATE - DATE(r.doc_date_utc)) > 60 GROUP BY r.customer_id, c.customer_name ORDER BY ar_overdue_balance DESC LIMIT 30 ; WITH revenue AS ( SELECT to_char(doc_date_utc, 'YYYY-MM') AS ym, SUM(COALESCE(amount, 0)) AS ship_amount FROM fact_sales_shipment WHERE doc_date_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(doc_date_utc, 'YYYY-MM') ), cost AS ( SELECT to_char(event_time_utc, 'YYYY-MM') AS ym, SUM(COALESCE(ABS(movement_qty) * unit_price, 0)) AS cost_amount FROM fact_inventory_movement WHERE sales_order_id IS NOT NULL AND COALESCE(movement_qty, 0) < 0 AND event_time_utc >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(event_time_utc, 'YYYY-MM') ) SELECT r.ym, r.ship_amount, c.cost_amount, (r.ship_amount - COALESCE(c.cost_amount, 0)) AS gross_profit_amount, CASE WHEN r.ship_amount > 0 THEN (r.ship_amount - COALESCE(c.cost_amount, 0)) / r.ship_amount ELSE NULL END AS gross_margin_rate FROM revenue r LEFT JOIN cost c ON c.ym = r.ym ORDER BY r.ym LIMIT 30 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-16 12:40:09 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-16 12:40:09 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-16 12:40:09 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
2026-01-16 12:40:11 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
2026-01-16 12:40:11 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: HumanResourcesAnalytics
2026-01-16 12:40:11 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
2026-01-16 12:40:11 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:138] - 正在调用测试SQL API: http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema
2026-01-16 12:40:11 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:139] - 请求参数: {
  "datasourceId": "19",
  "businessName": "HumanResourcesAnalytics",
  "businessDescription": "人力资源数据分析：提供月度在岗人数、招聘/离职趋势、产线部门离职率连续上升预警，以及岗位空缺天数分析。",
  "sqlTemplate": "WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ) SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, p.position, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department, p.position ORDER BY ym, p.department, p.position LIMIT 30 ; SELECT to_char(employment_day, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS hire_count FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL AND employment_day >= (CURRENT_DATE - INTERVAL '12 months') GROUP BY to_char(employment_day, 'YYYY-MM'), department, position ORDER BY ym, department, position LIMIT 30 ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ) SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, position, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department, position ORDER BY ym, department, position LIMIT 30 ; WITH months AS ( SELECT generate_series( date_trunc('month', CURRENT_DATE) - INTERVAL '11 months', date_trunc('month', CURRENT_DATE), INTERVAL '1 month' )::date AS month_start ), month_end AS ( SELECT month_start, (month_start + INTERVAL '1 month' - INTERVAL '1 day')::date AS month_end FROM months ), headcount AS ( SELECT to_char(me.month_start, 'YYYY-MM') AS ym, p.department, COUNT(DISTINCT p.person_id) AS headcount_active FROM month_end me JOIN dim_person p ON p.row_valid_from <= me.month_end AND p.row_valid_to > me.month_end AND p.status = 'ACTIVE' GROUP BY to_char(me.month_start, 'YYYY-MM'), p.department ), ordered AS ( SELECT person_id, department, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), exit_cnt AS ( SELECT to_char(exit_time, 'YYYY-MM') AS ym, department, COUNT(DISTINCT person_id) AS exit_count FROM exit_event WHERE exit_time >= (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') - INTERVAL '12 months' GROUP BY to_char(exit_time, 'YYYY-MM'), department ), rate AS ( SELECT h.ym, h.department, COALESCE(e.exit_count, 0) AS exit_count, h.headcount_active, CASE WHEN h.headcount_active > 0 THEN COALESCE(e.exit_count, 0)::numeric / h.headcount_active ELSE NULL END AS monthly_turnover_rate FROM headcount h LEFT JOIN exit_cnt e ON e.ym = h.ym AND e.department IS NOT DISTINCT FROM h.department ), flag AS ( SELECT r.*, LAG(monthly_turnover_rate, 1) OVER (PARTITION BY department ORDER BY ym) AS r_m1, LAG(monthly_turnover_rate, 2) OVER (PARTITION BY department ORDER BY ym) AS r_m2 FROM rate r ) SELECT ym, department, exit_count, headcount_active, monthly_turnover_rate FROM flag WHERE monthly_turnover_rate IS NOT NULL AND r_m1 IS NOT NULL AND r_m2 IS NOT NULL AND monthly_turnover_rate > r_m1 AND r_m1 > r_m2 ORDER BY department, ym LIMIT 30 ; WITH ordered AS ( SELECT person_id, department, position, status, row_valid_from, LAG(status) OVER (PARTITION BY person_id ORDER BY row_valid_from) AS prev_status FROM dim_person ), exit_event AS ( SELECT person_id, department, position, row_valid_from AS exit_time FROM ordered WHERE status = 'INACTIVE' AND COALESCE(prev_status, 'UNKNOWN') <> 'INACTIVE' ), hire_event AS ( SELECT department, position, employment_day AS hire_date, person_id FROM dim_person WHERE is_current = TRUE AND employment_day IS NOT NULL ), matched AS ( SELECT e.department, e.position, e.exit_time, ( SELECT MIN(h.hire_date) FROM hire_event h WHERE h.department IS NOT DISTINCT FROM e.department AND h.position IS NOT DISTINCT FROM e.position AND h.hire_date > DATE(e.exit_time) ) AS next_hire_date FROM exit_event e ) SELECT department, position, DATE(exit_time) AS exit_date, next_hire_date, (next_hire_date - DATE(exit_time)) AS vacancy_days FROM matched WHERE next_hire_date IS NOT NULL ORDER BY vacancy_days DESC LIMIT 30 ;",
  "parameters": {},
  "testParams": {}
}
2026-01-16 12:40:11 - httpx - INFO - [_client.py:1025] - HTTP Request: POST http://192.168.11.24:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema "HTTP/1.1 200 "
2026-01-16 12:40:11 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - INFO - [api_client.py:154] - 测试SQL API调用成功
2026-01-16 12:40:11 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
