在 Odoo 17 里点「打印 / 导出 PDF」,页面直接弹 Odoo Server Error,信息里写着 AccessError: You are not allowed to access 'xxx' (xxx).,或者报表能开但内容是一片空白。很多人第一反应是报表模板坏了、要改 QWeb,其实十次有九次根因在权限层——ACL 访问控制或 ir.rule 记录规则把记录挡掉了,跟报表本身没关系。
先看清是哪种报错
同样是打不开,现象分两类,排查方向完全不同:
| 报错现象 | 落在哪一层 | 典型原因 |
|---|---|---|
| 弹 AccessError,含模型名 | ACL 或 ir.rule | 组没勾读权限 / 记录规则 domain 太严 |
| 报表能开但内容空白 | 几乎都是 ir.rule | t-foreach 取的子记录全被规则过滤 |
一句话记:ACL 管「能不能碰这个模型」,ir.rule 管「能看哪些具体记录」。报表报错绝大多数落在后者。
第一步:从报错里抠出被挡的模型
AccessError 那行一定带模型名,比如 sale.order、account.move、stock.picking。先把它记下来,后面两步都围着它转。如果只是「报表空白」而不是报错,多半也是同一层规则把数据过滤光了,模型名可以从报表 XML 里 t-foreach 的对象反推出来。
第二步:查 ACL 访问控制
进「设置 → 技术 → 安全 → 访问控制列表(Access Rights)」,搜刚才那个模型,看出问题的用户所在组有没有勾「读」。没有就补一条:
# my_module/security/ir.model.access.csv
id,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sale_user,sale.order,group_sale_user,1,0,0,0
改完不用重启服务,刷新页面即可生效。
第三步:查 ir.rule 记录规则
这是重灾区。进「设置 → 技术 → 安全 → 记录规则(Record Rules)」,搜模型名,逐条看 domain_force。常见坑是规则写了 [('user_id','=',user.id)],但报表是定时任务或另一用户触发的,自然被挡。
临时验证:把可疑规则「Active」取消勾,再打印。能出就说明是它,再回来精修 domain,别直接删规则,否则相当于放权给所有用户。
第四步:多公司部署单独看
开了多公司的环境,报表常因 company_id 不匹配被全局规则挡。标准写法:
['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]
注意 company_ids 是 Odoo 按用户允许公司自动注入的变量,手写 user.company_id.id 在多公司下会漏掉其他公司记录,导致只看到自己公司、跨公司报表空白。
踩坑实录
给销售员加了「销售 / 用户」组,以为就能打印报价单,结果一点打印就 AccessError。翻到 记录规则 里一条全局规则 domain_force 写的是 [('company_id','=',user.company_id.id)],可报价单模型压根没设 company_id 字段——规则永远算 False,非 admin 全被挡。改成 [('company_id','in',[False]+user.company_ids.ids)] 后立刻恢复。教训:多公司规则别写死单个 company_id,否则一旦模型没这个字段就把人全挡了。
常见问题
Q1:为什么 admin 能打、普通用户不行?
admin 默认跳过所有 ir.rule(除非规则勾了「全局」且专门针对 admin)。普通用户要过 ACL + 记录规则两关,所以差异几乎都在规则上,先看域再看组。
Q2:改了规则还是报错,怎么办?
开「开发者模式」看「设置 → 技术 → 日志」,搜 AccessError 前后的 traceback,确认是模型层被挡,还是报表的 t-foreach 取了被挡的子记录(这种情况要查子模型规则)。
权限类排障讲究一处一处缩窄范围,思路理清了其实很快。更多 Odoo 与服务器运维实操,欢迎到 fenij.com 留言交流,遇到具体报错把完整 traceback 贴出来更好定位。