""" 商机管理模块 - Python后端实现 提供商机全生命周期管理和分析功能 """ import os import sys from datetime import datetime, date from decimal import Decimal import json # 模块元数据 __version__ = "1.0.0" __author__ = "Hermes Agent" __description__ = "商机管理模块提供销售跟进和商机全生命周期管理功能" def get_module_info(): """返回模块基本信息""" return { "name": "opportunity_management", "version": __version__, "description": __description__, "tables": ["opportunities", "sales_stages", "opportunity_stage_history"], "ui_files": ["opportunity_management.ui"] } def calculate_conversion_rate(stage_name): """ 计算指定阶段的历史转化率 Args: stage_name (str): 销售阶段名称 Returns: float: 转化率百分比 (0-100) """ # 这里会查询数据库获取历史转化率 # 默认实现返回预设值 stage_rates = { "初步接洽": 60.0, "需求确认": 70.0, "方案报价": 50.0, "合同谈判": 80.0, "成交": 100.0 } return stage_rates.get(stage_name, 0.0) def calculate_predicted_revenue(estimated_amount, probability): """ 计算预测收入 Args: estimated_amount (Decimal): 预估金额 probability (float): 成交概率百分比 Returns: Decimal: 预测收入 """ if estimated_amount is None or probability is None: return Decimal('0.00') return Decimal(str(estimated_amount)) * Decimal(str(probability)) / Decimal('100') def calculate_deviation_rate(predicted_amount, actual_amount): """ 计算预测偏差率 Args: predicted_amount (Decimal): 预测金额 actual_amount (Decimal): 实际成交金额 Returns: float: 偏差率百分比 (绝对值) """ if predicted_amount is None or actual_amount is None or predicted_amount == Decimal('0'): return 0.0 deviation = abs(predicted_amount - actual_amount) / predicted_amount * 100 return float(deviation) def validate_prediction_accuracy(deviation_rate, max_allowed_deviation=15.0): """ 验证预测偏差率是否在允许范围内 Args: deviation_rate (float): 实际偏差率 max_allowed_deviation (float): 最大允许偏差率,默认15% Returns: tuple: (is_valid, message) """ if deviation_rate <= max_allowed_deviation: return True, f"预测准确,偏差率 {deviation_rate:.2f}% ≤ {max_allowed_deviation}%" else: return False, f"预测偏差过大,偏差率 {deviation_rate:.2f}% > {max_allowed_deviation}%" def validate_opportunity_data(data): """ 验证商机数据的必填字段 Args: data (dict): 商机数据 Returns: tuple: (is_valid, error_message) """ required_fields = ['customer_name', 'estimated_amount', 'current_stage', 'expected_close_date'] for field in required_fields: if field not in data or not data[field]: return False, f"必填字段 '{field}' 不能为空" # 验证预计成交时间格式 if isinstance(data['expected_close_date'], str): try: datetime.strptime(data['expected_close_date'], '%Y-%m-%d') except ValueError: return False, "预计成交时间格式错误,应为 YYYY-MM-DD" # 验证预估金额 try: amount = Decimal(str(data['estimated_amount'])) if amount < 0: return False, "预估金额不能为负数" except: return False, "预估金额格式错误" return True, "" def get_funnel_analysis(region=None, owner_id=None): """ 获取销售漏斗分析数据 Args: region (str, optional): 区域筛选 owner_id (str, optional): 销售人员ID筛选 Returns: dict: 漏斗分析数据 """ # 这里会查询数据库获取实际数据 # 返回示例数据结构 return { "stage_counts": { "初步接洽": 25, "需求确认": 18, "方案报价": 12, "合同谈判": 8, "成交": 5 }, "stage_amounts": { "初步接洽": Decimal('250000.00'), "需求确认": Decimal('180000.00'), "方案报价": Decimal('120000.00'), "合同谈判": Decimal('80000.00'), "成交": Decimal('50000.00') }, "total_opportunities": 68, "total_amount": Decimal('680000.00'), "conversion_rates": { "初步接洽": 72.0, "需求确认": 66.7, "方案报价": 66.7, "合同谈判": 62.5 } } def get_prediction_accuracy(): """ 获取预测准确性分析数据 Returns: dict: 预测vs实际成交数据 """ # 返回示例数据 predicted = [120000, 150000, 180000, 200000, 160000, 190000] actual = [115000, 145000, 175000, 195000, 155000, 185000] # 计算偏差率 deviation_rates = [] accuracy_rates = [] for i in range(len(predicted)): pred = Decimal(str(predicted[i])) act = Decimal(str(actual[i])) deviation = calculate_deviation_rate(pred, act) deviation_rates.append(deviation) accuracy_rates.append(100.0 - deviation) # 验证整体偏差率是否满足要求 avg_deviation = sum(deviation_rates) / len(deviation_rates) if deviation_rates else 0.0 is_accurate, accuracy_message = validate_prediction_accuracy(avg_deviation) return { "months": ["1月", "2月", "3月", "4月", "5月", "6月"], "predicted": predicted, "actual": actual, "deviation_rates": deviation_rates, "accuracy_rates": accuracy_rates, "average_deviation": avg_deviation, "meets_accuracy_requirement": is_accurate, "accuracy_message": accuracy_message }