跳转至

跨版本兼容性(Odoo 10-19)

MCP 服务器会根据检测到的版本、版本类型和部署方式来解析模型名、字段名和能力。权威且可验证的来源是仓库中的 deltas 映射表(server/src/odoo_mcp/compat/deltas.py);本页只是它的摘要。

v1.5.0 新增

  • 权限策略会跟随重命名。 针对本映射表中一对被重命名或合并的名称中任一名称的规则,在所有版本上都同时适用于两者(account.invoice 和 account.move、stock.quant.package 和 stock.package、base.automation 和 base.action.rule 等),对其中任一名称的拒绝都会胜出。参见 优先级。
  • 沙箱矩阵(Odoo 10.0 至 19.0)也会对照每个真实的版本系列检查权限策略,并在某个系列缺少相应模型或字段时,跳过该项检查并说明原因。
  • Odoo 10 上的 odoo_add_automation 会填写 base.action.rule 的触发器字段,该版本将其命名为 kind(而不是 trigger)。

检测

  • 版本:common.version() 的主版本与次版本(server_version_info,或从 server_version 解析得到);主版本约束在 10-19 之间。稳定系列的次版本为 0,Odoo Online 的 saas~<主版本>.N 版本线为 N,这些版本线位于两个稳定系列之间:18.0 < saas~18.1 < … < saas~18.4 < 19.0。当 ODOO_TRANSPORT_PREF 为 auto 或 json2 时,读取版本既不登录也不使用已弃用的端点,因此不会在 Odoo 日志中留下任何记录:先用 Web 客户端自己的路由(POST /web/webclient/version_info,10.0 起),再用 GET /json/version(19.0+),最后才用经典的 common.version。jsonrpc 和 xmlrpc 仍然先用 common.version。传输层会保存未约束的版本系列(例如 20.0、saas~21.1),用于它自己的选择。
  • 版本类型:版本字符串中的 +e 后缀;若无,则探测 web_enterprise 模块(ir.module.module);若仍无,则为 unknown。
  • 部署方式:主机为 *.odoo.com ⇒ saas,否则为 onprem。 odoo_online_profile 还会说明该检测的可信程度(deployment_confidence):当版本字符串是 saas~ 版本线时为 version,因为只有 Odoo Online 运行这些版本线(此时即使在自有域名上也会报告 saas);当只有主机名起决定作用时为 host,因为 Odoo.sh 也使用 *.odoo.com,而一个位于自有域名之后、运行稳定系列的 Online 数据库看起来会像 onprem。

模型重命名

现代名称 历史名称 边界
account.move account.invoice 参见关于 v10 至 v12 的警告
account.move.line account.invoice.line 参见关于 v10 至 v12 的警告
stock.package stock.quant.package v19 新增

对于 stock.package,两种名称你都可以传入;resolver 会返回在目标实例中有效的那个。

会计:account.move 与 account.invoice 并不是简单的重命名

在 Odoo 13 中,发票模型 account.invoice 被 合并 进了会计凭证模型 account.move(且 account.invoice.line 被合并进 account.move.line)。但在 Odoo 10 至 12 中,二者作为语义不同的两个模型共存:account.move 是 会计凭证,而 account.invoice 是 发票。

因此,在全局将一个名称替换为另一个是危险的,尤其是在写入和删除 时(odoo_create/odoo_write/odoo_unlink):一个本意针对发票的操作,在 v10 至 v12 上可能落到会计凭证上(或反之)。

在 v10 至 v12 实例上的实用规则:显式命名你想要的模型(发票用 account.invoice,会计凭证用 account.move),并在写入前用 odoo_fields_get 加以验证。在 v13 及更高版本中只存在 account.move,因此这种歧义随之消失。

resolver 已经遵循这一规则:仅在 v13+ 上将 account.invoice 映射为 account.move,并且从不将 account.move 反向改写。

字段变更

模型 字段 变更 边界
account.move.line analytic_account_id → analytic_distribution 重命名 v16
product.template uom_po_id 已移除(使用 uom_id) saas~18.1(Online)与 19.0
res.partner company_type 已移除(使用 is_company) saas~19.1(Online);19.0 中仍存在

这两个边界已对照 Odoo 公开源代码中从 16.0 到 saas-19.4 的每个稳定分支与 saas 分支进行核实。

已移除的字段会连同一条 dropped_fields 警告从查询中被丢弃,而不会让整个调用失败。

能力

能力 可用性
api_key_auth Odoo ≥ 14(更早版本需要密码)
update_field_translations Odoo ≥ 16(更早版本使用带语言上下文的写入)

API keys 在 /jsonrpc 与 /xmlrpc/2 上同样被接受(两者都调用 Odoo 的 dispatch_rpc,14 至 19),并且是 JSON-2 唯一接受的凭据。当代理拦截或改动 /jsonrpc 时,auto 传输方式仍会回退 到 XML-RPC。

方法

方法 变更 替代做法
name_get v17 弃用,v18 移除 读取 display_name(10 至 19)
read_group(经典) 19.0 弃用;saas~19.1 至 saas~19.4 中不存在;在 20.0 中以 _read_group 的签名回归 formatted_read_group(saas~18.4+)
formatted_read_group saas~18.4 新增(web 模块)
check_access_rights 19.0 弃用,自 saas~19.1 起移除 has_access(18.0+)

方法条目同样是数据(METHOD_DELTAS)。odoo_read_group 自 saas~18.4 起调用 formatted_read_group,并保留经典的参数和输出;参见 工具参考。

RPC 端点

v1.4.0 新增:JSON-2 传输

Odoo 19 将 /xmlrpc 和 /jsonrpc 标记为弃用(每次调用都会在 Odoo 服务器日志中留下一条警告),并且 Odoo 22 和 Odoo Online saas~21.1 会移除它们。它们的替代方案 JSON-2(/json/2/<模型>/<方法>)自 saas~18.4 和 19.0 起存在,并且只接受 API key。自 v1.4.0 起,插件会自动使用它。

端点 版本系列 凭据 说明
/xmlrpc/2 10.0 至 21.0 密码,或 API key(14+) 19.0 弃用(移入自动安装的 rpc 模块);每次调用都会在 Odoo 日志中留下一条警告;在 Odoo 22 和 Odoo Online saas~21.1 中移除
/jsonrpc 12.0 至 21.0 密码,或 API key(14+) 与 /xmlrpc/2 相同(两者都经过 dispatch_rpc,14 至 19)
JSON-2 POST /json/2/<模型>/<方法> saas~18.4、19.0+ 仅 API key(Authorization: bearer) 只接受具名参数;X-Odoo-Database 请求头;没有弃用警告

auto 传输方式

当 ODOO_TRANSPORT_PREF=auto(选项 Transport preference,默认值)时,服务器根据未约束的版本系列、凭据类型以及 ODOO_URL 是否带有 user:pass@(用于网关的基本认证,它需要与 JSON-2 的 key 相同的 Authorization 请求头)来决定:

情况 顺序 说明
saas~18.4 之前(Odoo 10 至 18,saas~18.1 至 18.3) JSON-RPC → XML-RPC 与以前相同
saas~18.4 / 19.0+,有 API key 且没有 user:pass@ JSON-2 → JSON-RPC → XML-RPC 第一次登录后固定为 JSON-2;只有当代理拦截 JSON-2 时才使用 JSON-RPC 和 XML-RPC
同一范围,使用密码或 user:pass@ JSON-RPC → XML-RPC 自 19.0 起,odoo_version 会返回附带解决办法的 transport_notice,服务器也会记录一次
saas~21.1 / Odoo 22+,有 API key 仅 JSON-2 已经没有其他端点
saas~21.1 / Odoo 22+,使用密码或 user:pass@ ConfigError 设置一个 API key 并去掉 user:pass@

json2 强制使用 JSON-2;jsonrpc 和 xmlrpc 强制使用对应的端点。它们都不会自行切换传输方式。只有当一次调用不会因此被执行两次时,它才会转到另一种传输方式:版本、登录和读取总是如此;写入仅当请求从未到达 Odoo 时才会转移。调用频率限制(HTTP 429)从不切换传输方式:读取会等待 Retry-After(最多 30 秒,3 次尝试),写入则会被报告。

在 JSON-2 上,odoo_execute 在 ids 中接收记录 id,在 kwargs 中按名称接收其他参数。JSON-2 会把 @api.readonly 方法发送到只读游标,当 Odoo 主机设置了 db_replica_host 时,这个游标就是一个副本:紧接在写入之后的读取在那里可能会有延迟。

Odoo Online 工具

六个 Odoo Online 工具在任何 Odoo 10-19 上都可用,并按版本降级(详见 工具参考):

工具 各版本说明
odoo_online_profile API keys 自 14 起,过期时间自 18 起;在 19.0 上只有管理员能读取模块列表(对其他用户返回 null,并由 unavailable 说明原因)
odoo_api_catalog /doc-bearer 需要 19.0+ 和管理员的 API key;普通用户得到内置的对照表
odoo_access_check 自 18 起按记录检查(has_access);10-17 使用 check_access_rights;导出组自 16 起
odoo_record_documents 发票已保存的 PDF 自 17 起;这些工具不渲染报表(odoo_report 已弃用,且从未能通过 RPC 工作)
odoo_import_preview 16-19,通过 JSON-RPC 或 JSON-2
odoo_import 12-19,通过 JSON-RPC 或 JSON-2;在所有版本上都是原子操作

版本类型

Enterprise 专属的模型(启发式列表:documents.document、sign.request、account.consolidation.period、quality.check、helpdesk.ticket、planning.slot、appraisal.appraisal)在实例被检测为 Community 时会抛出 CompatError。运行时的模块探测是权威来源。

"best-effort" 边界

尚未对照 Odoo 源代码或真实实例确认的边界会标注为 best-effort。由于该映射表是由表驱动测试所覆盖的纯数据,修正一个边界只需一行编辑外加一行测试(参见 贡献)。此外,沙箱矩阵工作流每周都会将 res.partner 条目与真实的 Odoo Community 10.0-19.0 进行比对;自 v1.5.0 起也会检查权限策略:odoo_version 的 policy 块对照 --check-policy、需要 Odoo 元数据的 standard 拒绝、每个已安装委托模型的链接字段、builder 下的 odoo_add_field 和 odoo_add_automation(10.0 上为 base.action.rule),以及对本次运行审计日志的 --verify-audit;自 v1.5.1 起,还会检查按位置传递的上下文中值为列表的 default_<字段> 是否被拒绝。自 v1.6.0 起,服务器在 14.0 起的每个版本系列上用沙箱的 API key 登录(在 19.0 上通过 JSON-2),在 10.0 至 13.0 上用密码登录;工作流会检查两者都不会进入审计日志,并检查第二次 sandbox up 会保留这个 key。

实践中

针对 现代名称 编写代码,但 v10 至 v12 的会计模型除外:account.invoice/account.move 是合并而非重命名。在 v10 至 v12 上请明确写出你真正想要的模型(发票用 account.invoice,日记账分录用 account.move),并在写入前用 odoo_fields_get 验证。解析器(resolve_model)仅在 v13+ 将 account.invoice → account.move 映射,绝不会把 account.move 反向改写。如果一次查询返回了 dropped_fields,说明该字段在目标版本中不存在,请在上方表格中查找等价的现代名称。自 v1.5.0 起,权限策略中针对 account.move 的规则在 v10 至 v12 上也会限制 account.invoice,反之亦然。在 v10 至 v12 上,请按名称传递上下文(放在 kwargs 中):这些版本会把按位置传递的对象当作上下文,自 v1.5.1 起策略也会把它当作上下文来检查,自 v1.6.0 起还会拒绝它的既不是模型字段、也不是允许的上下文键的键(参见 已知限制 10)。

Skill 参考:/odoo-tools:odoo-crossversion。