Odoo如何跨函数更新payrun_chatter_log创建记录的body字段
问题说明
在custom_button函数中更新payrun_chatter_log()方法创建的mail.message记录的body字段时更新失败,原有实现代码如下:
def payrun_chatter_log(self): subtype = self.env['mail.message.subtype'].search([('id','=', '2')]) vals = { 'date': fields.datetime.now(), 'email_from': self.env.user.email_formatted, 'author_id': self.env.user.id, 'message_type': 'notification', 'subtype_id': subtype.id, 'is_internal': True, 'model': 'custom.module', 'res_id': self.id, 'body': 'Test' } self.env['mail.message'].create(vals) def custom_button(self): chatter = self.env['mail.message'].search([('res_id', '=', self.id)]) message = 'Custom Message here' chatter.update({'body': message}) return super(CustomModule, self).custom_button()
失败原因
- 搜索条件仅匹配
res_id,会拉取当前单据下所有消息记录,包含系统生成的、当前用户无编辑权限的记录,批量更新时会被ORM权限规则拦截,导致整体操作失败。 mail.message模型默认有严格的写入权限控制,普通用户仅能编辑自身创建的、在允许编辑时间窗口内的消息,非管理员/非作者直接修改历史消息会被拦截。- 创建消息时未保存返回的消息实例ID,后续更新无法精准定位目标记录,容易匹配到非目标消息。
修复方案
- 创建日志消息时保存返回的消息ID,优先通过关联字段绑定到当前单据,避免后续搜索匹配错误。
- 搜索目标消息时补全过滤条件,精准定位到自己创建的目标日志,不要全量拉取所有关联消息。
- 对目标单条记录使用提权操作绕过权限拦截,禁止对不确定范围的记录集批量提权修改。
修复后参考代码:
from odoo import fields, models class CustomModule(models.Model): _name = 'custom.module' # 新增字段存储创建的日志消息ID,方便后续精准定位 payrun_log_message_id = fields.Many2one('mail.message', string='薪资运行日志消息') def payrun_chatter_log(self): # 主键查询直接用browse,比search效率更高,ID=2是Odoo内置的讨论子类型,固定存在 subtype = self.env['mail.message.subtype'].browse(2) vals = { 'date': fields.datetime.now(), 'email_from': self.env.user.email_formatted, 'author_id': self.env.user.id, 'message_type': 'notification', 'subtype_id': subtype.id, 'is_internal': True, 'model': 'custom.module', 'res_id': self.id, 'body': 'Test' } # 保存创建的消息记录到关联字段 self.payrun_log_message_id = self.env['mail.message'].create(vals) def custom_button(self): new_message_content = 'Custom Message here' # 直接通过关联字段定位目标消息,提权后更新 if self.payrun_log_message_id: self.payrun_log_message_id.sudo().write({'body': new_message_content}) # 不想新增字段的话,搜索时补全所有过滤条件精准匹配目标记录 # target_log = self.env['mail.message'].search([ # ('model', '=', 'custom.module'), # ('res_id', '=', self.id), # ('author_id', '=', self.env.user.id), # ('is_internal', '=', True), # ('message_type', '=', 'notification'), # ('body', '=', 'Test') # ], limit=1) # if target_log: # target_log.sudo().write({'body': new_message_content}) return super(CustomModule, self).custom_button()
补充说明
- Odoo 16及以上版本对
mail.message增加了额外的防篡改校验,修改历史消息必须使用sudo()提权才能正常写入。 - 提权操作仅针对确定的单条目标记录执行,避免扩大权限范围误改系统其他消息数据。
内容的提问来源于stack exchange,提问作者Kai Ning
相关产品推荐
相关产品推荐

