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

Odoo 15转16模块迁移:operating_unit_id字段权限报错求助

Odoo 15→16迁移:上下文引用权限组字段报错解决

问题场景

将模块从Odoo 15.0迁移至16.0版本后,在XML视图中为operating_unit_id字段添加权限组operating_unit.group_multi_operating_unit,出现上下文验证报错。该字段已在purchase.order.line和purchase.order模型中创建,删除权限组可正常运行但业务不允许删除。

原视图代码

<record id="purchase_order_form" model="ir.ui.view">
    <field name="purchase_order_form">purchase_order_form</field>
    <field name="model">purchase.order</field>
    <field name="inherit_id" ref="purchase.purchase_order_form" />
    <field name="arch" type="xml">
        <field name="partner_ref" position="after">
            <field
name="requesting_operating_unit_id"
groups="operating_unit.group_multi_operating_unit"
/>
            <field
name="operating_unit_id"
groups="operating_unit.group_multi_operating_unit"
/>
        </field>
        <field name="order_line" position="attributes">
            <attribute name="context">{"default_state": "draft", "default_operating_unit_id": operating_unit_id}</attribute>
        </field>
    </field>
</record>

报错信息

Traceback (most recent call last):
  File "/opt/odoo/custom/src/odoo/odoo/http.py", line 1583, in _serve_db
    return service_model.retrying(self._serve_ir_http, self.env)
  File "/opt/odoo/custom/src/odoo/odoo/service/model.py", line 134, in retrying
    result = func()
  File "/opt/odoo/custom/src/odoo/odoo/http.py", line 1610, in _serve_ir_http
    response = self.dispatcher.dispatch(rule.endpoint, args)
  File "/opt/odoo/custom/src/odoo/odoo/http.py", line 1807, in dispatch
    result = self.request.registry['ir.http']._dispatch(endpoint)
  File "/opt/odoo/custom/src/odoo/odoo/addons/base/models/ir_http.py", line 154, in _dispatch
    result = endpoint(**request.params)
  File "/opt/odoo/custom/src/odoo/odoo/http.py", line 696, in route_wrapper
    result = endpoint(self, *args, **params_ok)
  File "/opt/odoo/auto/addons/web/controllers/dataset.py", line 46, in call_button
    action = self._call_kw(model, method, args, kwargs)
  File "/opt/odoo/auto/addons/web/controllers/dataset.py", line 33, in _call_kw
    return call_kw(request.env[model], method, args, kwargs)
  File "/opt/odoo/custom/src/odoo/odoo/api.py", line 461, in call_kw
    result = _call_kw_multi(method, model, args, kwargs)
  File "/opt/odoo/custom/src/odoo/odoo/api.py", line 448, in _call_kw_multi
    result = method(recs, *args, **kwargs)
  File "<decorator-gen-75>", line 2, in button_immediate_upgrade
  File "/opt/odoo/custom/src/odoo/odoo/addons/base/models/ir_module.py", line 76, in check_and_log
    return method(self, *args, **kwargs)
  File "/opt/odoo/custom/src/odoo/odoo/addons/base/models/ir_module.py", line 678, in button_immediate_upgrade
    return self._button_immediate_function(type(self).button_upgrade)
  File "/opt/odoo/custom/src/odoo/odoo/addons/base/models/ir_module.py", line 615, in _button_immediate_function
    registry = modules.registry.Registry.new(self._cr.dbname, update_module=True)
  File "<decorator-gen-14>", line 2, in new
  File "/opt/odoo/custom/src/odoo/odoo/tools/func.py", line 87, in locked
    return func(inst, *args, **kwargs)
  File "/opt/odoo/custom/src/odoo/odoo/modules/registry.py", line 90, in new
    odoo.modules.load_modules(registry, force_demo, status, update_module)
  File "/opt/odoo/custom/src/odoo/odoo/modules/loading.py", line 483, in load_modules
    processed_modules += load_marked_modules(cr, graph,
  File "/opt/odoo/custom/src/odoo/odoo/modules/loading.py", line 371, in load_marked_modules
    loaded, processed = load_module_graph(
  File "/opt/odoo/custom/src/odoo/odoo/modules/loading.py", line 230, in load_module_graph
    load_data(cr, idref, mode, kind='data', package=package)
  File "/opt/odoo/custom/src/odoo/odoo/modules/loading.py", line 71, in load_data
    tools.convert_file(cr, package.name, filename, idref, mode, noupdate, kind)
  File "/opt/odoo/custom/src/odoo/odoo/tools/convert.py", line 763, in convert_file
    convert_xml_import(cr, module, fp, idref, mode, noupdate)
  File "/opt/odoo/custom/src/odoo/odoo/tools/convert.py", line 829, in convert_xml_import
    obj.parse(doc.getroot())
  File "/opt/odoo/custom/src/odoo/odoo/tools/convert.py", line 749, in parse
    self._tag_root(de)
  File "/opt/odoo/custom/src/odoo/odoo/tools/convert.py", line 709, in _tag_root
    raise ParseError(msg) from None  # Restart with "--log-handler odoo.tools.convert:DEBUG" for complete traceback
odoo.tools.convert.ParseError: while parsing /opt/odoo/auto/addons/purchase_operating_unit/views/purchase_order_view.xml:16
Error while validating view near:

<form string="Purchase Order" class="o_purchase_order" __validate__="1">
                <header>
                    <button name="action_rfq_send" states="draft" string="Send by Email" type="object" context="{'send_rfq':True}" class="oe_highlight" data-hotkey="g"/>

Field 'operating_unit_id' used in context ({'default_state': 'draft', 'default_operating_unit_id': operating_unit_id}) is restricted to the group(s) operating_unit.group_multi_operating_unit.

View error context:
{'file': '/opt/odoo/auto/addons/purchase_operating_unit/views/purchase_order_view.xml',
 'line': 1,
 'name': 'purchase_order_form',
 'view': ir.ui.view(1036,),
 'view.model': 'purchase.order',
 'view.parent': ir.ui.view(979,),
 'xmlid': 'purchase_order_form'}

问题原因

Odoo 16加强了视图上下文的权限验证:当在视图上下文中引用被权限组限制的字段时,即使视图中已添加该字段的权限组,上下文的引用仍会被拦截——因为上下文表达式在视图渲染时会被全局验证,不区分当前用户是否拥有对应权限组。

解决办法

方案1:模型层计算字段传递默认值(推荐)

在purchase.order模型中添加无权限限制的计算字段,封装权限判断逻辑:

from odoo import models, fields

class PurchaseOrder(models.Model):
    _inherit = 'purchase.order'

    ou_default_for_lines = fields.Many2one('operating.unit', compute='_compute_ou_default_for_lines')

    def _compute_ou_default_for_lines(self):
        for rec in self:
            rec.ou_default_for_lines = rec.operating_unit_id if self.env.user.has_group('operating_unit.group_multi_operating_unit') else False

修改视图上下文引用该计算字段:

<field name="order_line" position="attributes">
    <attribute name="context">{"default_state": "draft", "default_operating_unit_id": ou_default_for_lines}</attribute>
</field>

方案2:上下文直接加入权限判断

无需修改模型,直接在上下文表达式中加入权限组判断:

<field name="order_line" position="attributes">
    <attribute name="context">{"default_state": "draft", "default_operating_unit_id": env.user.has_group('operating_unit.group_multi_operating_unit') and operating_unit_id or False}</attribute>
</field>

注意事项

  • 方案1符合Odoo MVC架构,逻辑封装在模型层,更易维护;
  • 方案2实现快捷,适合快速修复场景;
  • 两种方案均保留operating_unit_id字段的权限组限制,同时绕过视图验证。

内容的提问来源于stack exchange,提问作者Tiago Rangel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:49:56