Odoo 15调度器无法自动运行及手动执行失效求助
Odoo 15 Cron调度器无法运行问题排查与解决
问题描述
用于发送聊天消息的Python函数通过自定义按钮可正常执行,但配置的Cron调度器既无法自动运行,手动点击「Run Manually」也无反应。
原Python函数代码
def action_send_notification(self): today_date = datetime.today() for i in self: if i.search([('date_end','<',today_date)]): message = "STR has been expired" recipient1 = i.employee_id.user_id.partner_id.id recipient2 = i.env['res.users'].sudo().search([('name', 'ilike', 'admin')]) channel = i.env['mail.channel'].channel_get([recipient1]) channel_id = i.env['mail.channel'].browse(channel["id"]) channel_id.message_post( body=message, message_type='comment', subtype_xmlid='mail.mt_comment',)
原Cron XML配置
<record id="STR_notif_expiration_scheduler" model="ir.cron"> <field name="name">STR Notif Expiration</field> <field name="user_id" ref="base.user_root" /> <field name="interval_number">1</field> <field name="interval_type">minutes</field> <field name="numbercall">-1</field> <field name="doall">0</field> <field name="model_id" ref="model_hr_str"/> <field name="code">model.action_send_notification()</field> <field name="priority">5</field> </record>
核心问题分析
- 方法上下文不匹配:按钮点击时,
self是当前表单/选中的hr.str记录集;但Cron调用model.action_send_notification()时,self是空记录集,导致for i in self循环直接跳过,代码完全未执行。 - 逻辑错误:
i.search([('date_end','<',today_date)])是用单条记录去搜索符合条件的记录,而非在模型级别筛选所有过期记录,逻辑冗余且不符合Cron批量处理的需求。 - 潜在时区问题:
datetime.today()使用本地时间,与Odoo存储的UTC时间可能存在偏差,导致过期判断不准确。
修复方案
1. 修改Python函数为模型级批量处理方法
调整逻辑,直接筛选所有过期记录并处理,同时修正时区问题、添加异常跳过逻辑:
from datetime import datetime from odoo import models, fields, api import logging _logger = logging.getLogger(__name__) class HrSTR(models.Model): _name = 'hr.str' # 原有字段定义... def action_send_notification(self): _logger.info("STR过期通知Cron开始执行") # 使用Odoo内置工具获取带时区的当前时间 today_date = fields.Datetime.now() # 批量搜索所有过期的STR记录 expired_records = self.search([('date_end', '<', today_date)]) # 获取admin用户(添加limit=1避免匹配多个结果) admin_user = self.env['res.users'].sudo().search([('name', 'ilike', 'admin')], limit=1) if not admin_user: _logger.warning("未找到name包含admin的用户,终止通知发送") return for str_rec in expired_records: # 检查员工是否关联用户 recipient_partner = str_rec.employee_id.user_id.partner_id if not recipient_partner: _logger.warning(f"STR记录{str_rec.id}的员工未关联用户,跳过通知") continue # 创建包含员工和admin的聊天频道 channel_data = self.env['mail.channel'].channel_get([recipient_partner.id, admin_user.partner_id.id]) channel = self.env['mail.channel'].browse(channel_data["id"]) # 发送消息 channel.message_post( body="STR has been expired", message_type='comment', subtype_xmlid='mail.mt_comment', ) _logger.info(f"STR过期通知Cron执行完成,共处理{len(expired_records)}条记录")
2. 验证Cron配置正确性
- 确认
model_id引用正确:进入设置 > 技术 > 数据库结构 > 模型,找到hr.str模型,查看其外部ID是否为model_hr_str,若不符需修改XML中的ref值。 - 检查Cron状态:打开Cron记录(
设置 > 技术 > 自动化 > 计划动作),确保「Active」选项已勾选。 - 权限确认:
user_id使用base.user_root(超级用户),权限足够执行所有操作,无需调整。
3. 调试与验证
- 查看日志:执行Cron后,进入
设置 > 技术 > 日志 > 日志,搜索STR过期通知相关日志,确认方法是否被调用、是否有报错信息。 - 手动测试:更新模块后,点击Cron的「Run Manually」,检查对应员工和admin的聊天窗口是否收到通知。
内容的提问来源于stack exchange,提问作者Satrio Lantip
相关产品推荐
相关产品推荐

