You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Odoo 14按钮触发短信发送失败,请求技术排查

短信未发送问题排查与解决方案

核心故障点排查

1. API密钥获取逻辑存在风险

  • 未处理请求失败场景:requests.get未校验响应状态码(如401认证失败、404接口不存在),若接口返回非200状态,r.text.split(':')[1]会抛出索引错误,或获取到无效密钥。
  • 路径参数拼接不规范:密码为空时,最终URL会以/结尾(如http://bulksms.skill.jobs/getkey/C2006884/),可能不符合第三方API的路径规则。
  • 硬编码空密码:若第三方API获取密钥必须验证密码,空密码会导致获取的密钥无效。

2. 短信发送请求未做错误校验

  • 未解析响应内容:仅打印r(响应对象),无法得知API返回的具体错误(如密钥无效、手机号格式错误、账户余额不足)。
  • 请求参数格式可能不符合要求:部分短信API要求用json格式传参而非data(表单格式),当前用data=params可能导致参数无法被正确解析。
  • 手机号格式不明确:self.restaurant_id.mobile可能缺少国际区号(如+880),或格式不符合API要求(如含非数字字符)。
  • 状态更新逻辑不合理:无论请求是否成功,直接将state设为sent,无法区分发送成功/失败状态。

3. 消息内容存在无效占位符

消息字符串中on .是无效内容(因注释了date_and_time变量),虽不直接导致发送失败,但可能影响短信可读性,甚至部分API会拦截格式异常的内容。


针对性解决方案

1. 修复API密钥获取逻辑

def get_api_key(self, url='', username='', password=''):
    if not url:
        url = 'http://bulksms.skill.jobs/getkey'
    if not username:
        username = 'C2006884'
    # 请确认第三方API是否需要密码,若需要补全正确密码
    if not password:
        password = "你的实际密码"
    
    # 使用查询参数而非路径参数(若API支持),避免空密码导致的路径异常
    params = {"username": username, "password": password}
    try:
        r = requests.get(url=url, params=params)
        # 校验响应状态码,非200则抛出异常
        r.raise_for_status()
        # 先检查返回格式是否符合预期,避免split出错
        if ':' not in r.text:
            raise ValueError("API返回格式异常,无法提取密钥")
        api_key = r.text.split(':')[1].strip()  # 去除可能的空格
        print(f"获取到API密钥: {api_key}")
        return api_key
    except Exception as e:
        print(f"获取API密钥失败: {str(e)}")
        # 可根据Odoo日志机制记录错误
        self.env.cr.rollback()
        raise UserError(f"获取短信API密钥失败: {str(e)}")

2. 优化短信发送请求与错误处理

def send_sms(self, api_endpoint='', senderid='', **kw):
    if not api_endpoint:
        api_endpoint = "https://bulksms.skill.jobs/smsapi"
    if not senderid:
        senderid = "8809612436715"
    
    # 校验手机号格式
    mobile = self.restaurant_id.mobile
    if not mobile or not mobile.strip().isdigit():
        raise UserError("餐厅手机号格式无效,请检查")
    # 确保手机号带国际区号(根据第三方API要求调整)
    if not mobile.startswith('+'):
        mobile = f"+{mobile}"
    
    # 修复消息内容的无效占位符
    message = "{customer_name} has sent a reservation in {restaurant_name}. Please call {customer_mobile} for further info.".format(
        customer_name=self.customer_id.name,
        restaurant_name=self.restaurant_id.name,
        customer_mobile=self.customer_id.mobile,
    )
    
    try:
        api_key = self.get_api_key()
        params = {
            "api_key": api_key,
            "type": "text",
            "contacts": mobile,
            "senderid": senderid,
            "msg": message
        }
        
        # 若API要求JSON格式,替换为json=params
        # r = requests.post(url=api_endpoint, json=params)
        r = requests.post(url=api_endpoint, data=params)
        r.raise_for_status()
        
        # 解析响应内容,确认发送状态
        response_data = r.json() if r.headers.get('content-type') == 'application/json' else r.text
        print(f"短信API响应: {response_data}")
        
        # 根据API返回的成功标识更新状态(需参考第三方API文档)
        if "success" in response_data.lower():
            self.state = 'sent'
        else:
            self.state = 'failed'
            raise UserError(f"短信发送失败: {response_data}")
        
        return True
    except Exception as e:
        print(f"短信发送失败: {str(e)}")
        self.state = 'failed'
        self.env.cr.rollback()
        raise UserError(f"短信发送失败: {str(e)}")

3. 额外排查步骤

  • 直接用Postman/curl调用第三方API,手动传入获取到的密钥、手机号、消息,验证API本身是否可正常发送短信,排除Odoo代码外的问题。
  • 检查第三方短信账户状态:是否有余额、是否绑定了正确的发送号码(senderid)、是否有发送限制(如地区、频次)。
  • 确认Odoo服务器可正常访问第三方API的域名(排查防火墙、网络代理问题)。

内容的提问来源于stack exchange,提问作者Nahid Jawad Angon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 03:35:19